umap-project 2.6.3__py3-none-any.whl → 2.7.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 (137) hide show
  1. umap/__init__.py +1 -1
  2. umap/admin.py +64 -1
  3. umap/asgi.py +15 -0
  4. umap/context_processors.py +1 -0
  5. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/cs_CZ/LC_MESSAGES/django.po +96 -92
  7. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/de/LC_MESSAGES/django.po +19 -18
  9. umap/locale/en/LC_MESSAGES/django.po +47 -43
  10. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  11. umap/locale/es/LC_MESSAGES/django.po +134 -128
  12. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  13. umap/locale/fr/LC_MESSAGES/django.po +51 -47
  14. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  15. umap/locale/pt/LC_MESSAGES/django.po +64 -60
  16. umap/management/commands/clean_tilelayer.py +152 -0
  17. umap/management/commands/purge_purgatory.py +28 -0
  18. umap/models.py +27 -2
  19. umap/settings/base.py +3 -1
  20. umap/static/umap/base.css +4 -4
  21. umap/static/umap/css/contextmenu.css +6 -1
  22. umap/static/umap/css/icon.css +7 -2
  23. umap/static/umap/css/importers.css +4 -0
  24. umap/static/umap/img/16-white.svg +9 -2
  25. umap/static/umap/img/16.svg +1 -181
  26. umap/static/umap/img/24-white.svg +1 -0
  27. umap/static/umap/img/24.svg +1 -0
  28. umap/static/umap/img/importers/cadastrefr.svg +23 -0
  29. umap/static/umap/img/source/16-white.svg +10 -3
  30. umap/static/umap/img/source/16.svg +753 -197
  31. umap/static/umap/img/source/24-white.svg +3 -2
  32. umap/static/umap/img/source/24.svg +3 -2
  33. umap/static/umap/js/modules/autocomplete.js +7 -3
  34. umap/static/umap/js/modules/browser.js +54 -1
  35. umap/static/umap/js/modules/caption.js +16 -5
  36. umap/static/umap/js/modules/data/features.js +176 -2
  37. umap/static/umap/js/modules/data/layer.js +57 -40
  38. umap/static/umap/js/modules/formatter.js +3 -2
  39. umap/static/umap/js/modules/global.js +2 -0
  40. umap/static/umap/js/modules/importer.js +3 -0
  41. umap/static/umap/js/modules/importers/cadastrefr.js +62 -0
  42. umap/static/umap/js/modules/importers/communesfr.js +15 -3
  43. umap/static/umap/js/modules/permissions.js +123 -93
  44. umap/static/umap/js/modules/rendering/layers/classified.js +2 -0
  45. umap/static/umap/js/modules/rendering/ui.js +60 -213
  46. umap/static/umap/js/modules/share.js +1 -3
  47. umap/static/umap/js/modules/slideshow.js +1 -1
  48. umap/static/umap/js/modules/sync/engine.js +371 -14
  49. umap/static/umap/js/modules/sync/hlc.js +106 -0
  50. umap/static/umap/js/modules/sync/updaters.js +18 -6
  51. umap/static/umap/js/modules/sync/websocket.js +1 -1
  52. umap/static/umap/js/modules/tableeditor.js +1 -1
  53. umap/static/umap/js/modules/ui/base.js +2 -2
  54. umap/static/umap/js/modules/ui/contextmenu.js +51 -18
  55. umap/static/umap/js/modules/urls.js +5 -1
  56. umap/static/umap/js/modules/utils.js +28 -4
  57. umap/static/umap/js/umap.controls.js +73 -52
  58. umap/static/umap/js/umap.core.js +3 -3
  59. umap/static/umap/js/umap.forms.js +3 -1
  60. umap/static/umap/js/umap.js +115 -124
  61. umap/static/umap/locale/br.js +13 -4
  62. umap/static/umap/locale/br.json +13 -4
  63. umap/static/umap/locale/ca.js +28 -15
  64. umap/static/umap/locale/ca.json +28 -15
  65. umap/static/umap/locale/cs_CZ.js +87 -78
  66. umap/static/umap/locale/cs_CZ.json +87 -78
  67. umap/static/umap/locale/de.js +17 -8
  68. umap/static/umap/locale/de.json +17 -8
  69. umap/static/umap/locale/en.js +13 -2
  70. umap/static/umap/locale/en.json +13 -2
  71. umap/static/umap/locale/es.js +330 -319
  72. umap/static/umap/locale/es.json +330 -319
  73. umap/static/umap/locale/eu.js +10 -3
  74. umap/static/umap/locale/eu.json +10 -3
  75. umap/static/umap/locale/fa_IR.js +11 -4
  76. umap/static/umap/locale/fa_IR.json +11 -4
  77. umap/static/umap/locale/fr.js +15 -4
  78. umap/static/umap/locale/fr.json +15 -4
  79. umap/static/umap/locale/hu.js +10 -3
  80. umap/static/umap/locale/hu.json +10 -3
  81. umap/static/umap/locale/pt.js +17 -8
  82. umap/static/umap/locale/pt.json +17 -8
  83. umap/static/umap/locale/pt_PT.js +13 -4
  84. umap/static/umap/locale/pt_PT.json +13 -4
  85. umap/static/umap/locale/zh_TW.js +13 -4
  86. umap/static/umap/locale/zh_TW.json +13 -4
  87. umap/static/umap/map.css +44 -29
  88. umap/static/umap/unittests/hlc.js +165 -0
  89. umap/static/umap/unittests/sync.js +321 -15
  90. umap/static/umap/unittests/utils.js +47 -0
  91. umap/static/umap/vars.css +2 -1
  92. umap/static/umap/vendors/colorbrewer/colorbrewer.js +309 -317
  93. umap/static/umap/vendors/dompurify/purify.es.js +15 -16
  94. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  95. umap/static/umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js +111 -80
  96. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +2 -2
  97. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +1 -1
  98. umap/static/umap/vendors/simple-statistics/simple-statistics.min.js +1 -1
  99. umap/static/umap/vendors/simple-statistics/simple-statistics.min.js.map +1 -1
  100. umap/templates/umap/css.html +0 -2
  101. umap/templates/umap/dashboard_menu.html +4 -2
  102. umap/templates/umap/js.html +0 -5
  103. umap/templates/umap/map_detail.html +2 -2
  104. umap/tests/fixtures/test_upload_data.csv +2 -2
  105. umap/tests/integration/test_anonymous_owned_map.py +1 -0
  106. umap/tests/integration/test_basics.py +1 -1
  107. umap/tests/integration/test_browser.py +69 -7
  108. umap/tests/integration/test_caption.py +3 -3
  109. umap/tests/integration/test_circles_layer.py +12 -0
  110. umap/tests/integration/test_datalayer.py +2 -1
  111. umap/tests/integration/test_draw_polygon.py +17 -9
  112. umap/tests/integration/test_draw_polyline.py +12 -8
  113. umap/tests/integration/test_edit_datalayer.py +5 -8
  114. umap/tests/integration/test_edit_map.py +2 -2
  115. umap/tests/integration/test_edit_marker.py +1 -1
  116. umap/tests/integration/test_facets_browser.py +3 -3
  117. umap/tests/integration/test_import.py +1 -0
  118. umap/tests/integration/test_map.py +1 -0
  119. umap/tests/integration/test_owned_map.py +1 -1
  120. umap/tests/integration/test_view_marker.py +63 -0
  121. umap/tests/integration/test_view_polygon.py +12 -12
  122. umap/tests/integration/test_websocket_sync.py +65 -3
  123. umap/tests/test_clean_tilelayer.py +83 -0
  124. umap/tests/test_datalayer.py +24 -0
  125. umap/tests/test_map_views.py +20 -0
  126. umap/tests/test_purge_purgatory.py +25 -0
  127. umap/tests/test_websocket_server.py +22 -0
  128. umap/urls.py +5 -1
  129. umap/views.py +6 -3
  130. umap/websocket_server.py +130 -27
  131. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/METADATA +18 -14
  132. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/RECORD +135 -127
  133. umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.css +0 -1
  134. umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.js +0 -7
  135. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/WHEEL +0 -0
  136. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/entry_points.txt +0 -0
  137. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/licenses/LICENSE +0 -0
umap/static/umap/map.css CHANGED
@@ -500,7 +500,9 @@ ul.photon-autocomplete {
500
500
  }
501
501
  .leaflet-container .leaflet-control-edit-save,
502
502
  .leaflet-container .leaflet-control-edit-cancel,
503
- .leaflet-container .leaflet-control-edit-disable {
503
+ .leaflet-container .leaflet-control-edit-disable,
504
+ .leaflet-container .leaflet-control-connected-peers
505
+ {
504
506
  display: block;
505
507
  border: none;
506
508
  font-size: 12px;
@@ -510,9 +512,17 @@ ul.photon-autocomplete {
510
512
  line-height: 30px;
511
513
  padding: 0 20px;
512
514
  }
515
+ .leaflet-container .leaflet-control-connected-peers,
516
+ .dark [type="button"].leaflet-control-connected-peers:hover
517
+ {
518
+ background-color: var(--color-lightCyan);
519
+ color: var(--color-dark);
520
+ }
521
+
513
522
  .leaflet-container .leaflet-control-edit-disable:before,
514
523
  .leaflet-container .leaflet-control-edit-save:before,
515
- .leaflet-container .leaflet-control-edit-cancel:before {
524
+ .leaflet-container .leaflet-control-edit-cancel:before,
525
+ .leaflet-container .leaflet-control-connected-peers:before {
516
526
  display: inline-block;
517
527
  width: 19px;
518
528
  height: 24px;
@@ -523,9 +533,15 @@ ul.photon-autocomplete {
523
533
  content: ' ';
524
534
  text-align: center;
525
535
  }
536
+
537
+ .leaflet-container .leaflet-control-connected-peers:before {
538
+ background-image: url('./img/16.svg');
539
+ }
540
+
526
541
  .leaflet-container .leaflet-control-edit-disable span,
527
542
  .leaflet-container .leaflet-control-edit-save span,
528
- .leaflet-container .leaflet-control-edit-cancel span {
543
+ .leaflet-container .leaflet-control-edit-cancel span,
544
+ .leaflet-container .leaflet-control-connected-peers span{
529
545
  margin-inline-start: 10px;
530
546
  }
531
547
  .leaflet-container .leaflet-control-edit-save:before {
@@ -534,8 +550,12 @@ ul.photon-autocomplete {
534
550
  .leaflet-container .leaflet-control-edit-disable:before {
535
551
  background-position: -50px -25px;
536
552
  }
553
+ .leaflet-container .leaflet-control-connected-peers:before {
554
+ background-position: -2px -95px;
555
+ }
537
556
  .leaflet-container .leaflet-control-edit-cancel,
538
- .leaflet-container .leaflet-control-edit-disable {
557
+ .leaflet-container .leaflet-control-edit-disable,
558
+ .leaflet-container .leaflet-control-connected-peers{
539
559
  border: 0.5px solid rgba(153, 153, 153, 0.40);
540
560
  }
541
561
  .leaflet-container .leaflet-control-edit-cancel:hover,
@@ -592,17 +612,16 @@ ul.photon-autocomplete {
592
612
  left: 0;
593
613
  right: 0;
594
614
  height: 46px;
595
- background-color: var(--color-darkGray);
596
615
  padding: 0 10px;
597
616
  text-align: start;
598
617
  line-height: var(--control-size);
599
618
  cursor: auto;
600
619
  border-bottom: 1px solid #222;
601
620
  z-index: var(--zindex-panels);
602
- opacity: 0.98;
603
- color: #fff;
604
621
  display: flex;
605
622
  justify-content: space-between;
623
+ background-color: var(--background-color);
624
+ color: var(--text-color);
606
625
  }
607
626
  .umap-left-edit-toolbox,
608
627
  .umap-right-edit-toolbox {
@@ -820,7 +839,6 @@ a.umap-control-caption,
820
839
  .umap-browser .off .feature {
821
840
  display: none;
822
841
  }
823
- .umap-facet-search .formbox,
824
842
  .umap-browser .datalayer {
825
843
  margin-bottom: 2px;
826
844
  border-radius: 2px;
@@ -831,7 +849,7 @@ a.umap-control-caption,
831
849
  .umap-browser.dark .datalayer ul {
832
850
  border: 1px solid #232729;
833
851
  }
834
- .umap-browser h5, .umap-facet-search h5 {
852
+ .umap-browser h5 {
835
853
  margin-bottom: 0;
836
854
  overflow: hidden;
837
855
  padding-inline-start: 5px;
@@ -849,7 +867,7 @@ a.umap-control-caption,
849
867
  .umap-browser h5 span {
850
868
  margin-inline-start: 10px;
851
869
  }
852
- .umap-browser li, .umap-facet-search li {
870
+ .umap-browser li {
853
871
  padding: 2px 0;
854
872
  white-space: nowrap;
855
873
  overflow: hidden;
@@ -867,13 +885,15 @@ a.umap-control-caption,
867
885
  -moz-box-sizing:border-box;
868
886
  -webkit-box-sizing:border-box;
869
887
  box-sizing: border-box;
870
- background: none;
871
888
  display: inline-block;
872
889
  padding: 0;
873
890
  width: 24px;
874
891
  text-align: center;
875
892
  margin-inline-start: 5px;
876
893
  }
894
+ .umap-browser .marker .feature-color {
895
+ background: none;
896
+ }
877
897
  .umap-browser.dark .datalayer .feature-color {
878
898
  box-shadow: 0 0 2px 0 #999 inset;
879
899
  }
@@ -884,18 +904,6 @@ a.umap-control-caption,
884
904
  font-style: normal;
885
905
  font-weight: bold;
886
906
  }
887
- .umap-browser .polygon .feature-color,
888
- .umap-browser .polyline .feature-color {
889
- box-shadow: 0 0 2px 0 black inset;
890
- background-image: url('./img/24.svg');
891
- background-size: 500%;
892
- }
893
- .umap-browser .polyline .feature-color {
894
- background-position: -72px -23px;
895
- }
896
- .umap-browser .polygon .feature-color {
897
- background-position: -48px -25px;
898
- }
899
907
  .umap-browser .datalayer-toggle-list {
900
908
  float: inline-end;
901
909
  margin-inline-end: 5px;
@@ -925,6 +933,16 @@ a.umap-control-caption,
925
933
  .umap-caption .umap-map-author {
926
934
  padding-inline-start: 31px;
927
935
  }
936
+ .umap-browser .main-toolbox {
937
+ padding-left: 4px; /* Align with toolbox below */
938
+ border-top: 1px solid var(--color-mediumGray);
939
+ margin-top: var(--box-margin);
940
+ padding-top: 3px;
941
+ padding-bottom: 3px;
942
+ }
943
+ .umap-browser .main-toolbox i {
944
+ cursor: pointer;
945
+ }
928
946
 
929
947
 
930
948
  /* ********************************* */
@@ -982,18 +1000,18 @@ a.umap-control-caption,
982
1000
  vertical-align: middle;
983
1001
  }
984
1002
 
985
- .datalayer-legend {
1003
+ .caption-item {
986
1004
  color: #555;
987
1005
  padding: 6px 8px;
988
1006
  box-shadow: 0 0 3px rgba(0,0,0,0.2);
989
1007
  border-radius: 1px;
990
1008
  }
991
- .datalayer-legend ul {
1009
+ .caption-item ul {
992
1010
  list-style-type: none;
993
1011
  padding: 0;
994
1012
  margin: 0;
995
1013
  }
996
- .datalayer-legend .circles-layer-legend {
1014
+ .caption-item .circles-layer-legend {
997
1015
  padding: var(--box-padding);
998
1016
  }
999
1017
  .circles-layer-legend li {
@@ -1499,9 +1517,6 @@ span.popup-icon {
1499
1517
  .umap-main-edit-toolbox .umap-user {
1500
1518
  margin-inline-end: 10px;
1501
1519
  }
1502
- .umap-main-edit-toolbox .umap-user:after {
1503
- display: none;
1504
- }
1505
1520
  }
1506
1521
  @media all and (max-width: 640px) {
1507
1522
  .umap-main-edit-toolbox .umap-user {
@@ -0,0 +1,165 @@
1
+ import { describe, it } from 'mocha'
2
+ import sinon from 'sinon'
3
+
4
+ import pkg from 'chai'
5
+ const { expect } = pkg
6
+
7
+ import { HybridLogicalClock } from '../js/modules/sync/hlc.js'
8
+
9
+ describe('HybridLogicalClock', () => {
10
+ let clock
11
+
12
+ describe('#parse', () => {
13
+ it('should reject invalid values', () => {
14
+ clock = new HybridLogicalClock()
15
+ expect(() => clock.parse('invalid')).to.throw()
16
+ expect(() => clock.parse('123:456')).to.throw()
17
+ expect(() => clock.parse('123:456:789:000')).to.throw()
18
+ })
19
+
20
+ it('should parse correct values', () => {
21
+ clock = new HybridLogicalClock()
22
+ const result = clock.parse('1625097600000:42:abc-123')
23
+ expect(result).to.deep.equal({
24
+ walltime: '1625097600000',
25
+ nn: 42,
26
+ id: 'abc-123',
27
+ })
28
+ })
29
+
30
+ it('should default to 0 for nn if none is provided', () => {
31
+ clock = new HybridLogicalClock()
32
+ const result = clock.parse('1625097600000::abc-123')
33
+ expect(result).to.deep.equal({
34
+ walltime: '1625097600000',
35
+ nn: 0,
36
+ id: 'abc-123',
37
+ })
38
+ })
39
+ })
40
+
41
+ describe('#serialize', () => {
42
+ it('should correctly serialize the clock', () => {
43
+ clock = new HybridLogicalClock(1625097600000, 42, 'abc-123')
44
+ expect(clock.serialize()).to.equal('1625097600000:42:abc-123')
45
+ })
46
+ })
47
+
48
+ describe('#tick', () => {
49
+ it('should increment walltime when current time is greater', () => {
50
+ const now = Date.now()
51
+ clock = new HybridLogicalClock(now - 1000, 0, 'test')
52
+ const result = clock.tick()
53
+ const parsed = clock.parse(result)
54
+ expect(parsed.walltime).to.be.at.least(now.toString())
55
+ expect(parsed.nn).to.equal(0)
56
+ })
57
+
58
+ it('should increment nn when current time is not greater', () => {
59
+ const now = Date.now()
60
+ clock = new HybridLogicalClock(now, 5, 'test')
61
+ sinon.useFakeTimers(now)
62
+ const result = clock.tick()
63
+ const parsed = clock.parse(result)
64
+ expect(parsed.walltime).to.equal(now.toString())
65
+ expect(parsed.nn).to.equal(6)
66
+ sinon.restore()
67
+ })
68
+ })
69
+
70
+ describe('#receive', () => {
71
+ it("should use current time when it's greater than both local and remote", () => {
72
+ const now = Date.now()
73
+ clock = new HybridLogicalClock(now - 1000, 0, 'local')
74
+ const result = clock.receive(`${now - 500}:0:remote`)
75
+ expect(result.walltime).to.be.at.least(now)
76
+ expect(result.nn).to.equal(0)
77
+ expect(result.id).to.equal('local')
78
+ })
79
+
80
+ it('should increment nn when local and remote times are equal', () => {
81
+ const now = Date.now()
82
+ // mock the clock to be the same time
83
+ sinon.useFakeTimers(now)
84
+ clock = new HybridLogicalClock(now, 5, 'local')
85
+ const result = clock.receive(`${now}:7:remote`)
86
+ expect(result.walltime).to.be.at.least(now)
87
+ expect(result.nn).to.equal(8)
88
+ expect(result.id).to.equal('local')
89
+ })
90
+
91
+ it('should use remote time and increment nn when remote time is greater', () => {
92
+ const now = Date.now()
93
+ clock = new HybridLogicalClock(now - 1000, 5, 'local')
94
+ const result = clock.receive(`${now}:7:remote`)
95
+ expect(result.walltime).to.be.least(now.toString())
96
+ expect(result.nn).to.equal(8)
97
+ expect(result.id).to.equal('local')
98
+ })
99
+
100
+ it('should increment local nn when local time is greater', () => {
101
+ const now = Date.now()
102
+ clock = new HybridLogicalClock(now, 5, 'local')
103
+ const result = clock.receive(`${now - 1000}:7:remote`)
104
+ expect(result.walltime).to.be.least(now)
105
+ if (result.walltime > now) {
106
+ expect(result.nn).to.equal(5)
107
+ }
108
+ else {
109
+ expect(result.nn).to.equal(6)
110
+ }
111
+ expect(result.id).to.equal('local')
112
+ })
113
+ })
114
+
115
+ it('should maintain causal order across multiple operations', () => {
116
+ const hlc = new HybridLogicalClock()
117
+
118
+ // Simulate a sequence of events
119
+ const event1 = hlc.tick()
120
+
121
+ // Simulate some time passing
122
+ const clock = sinon.useFakeTimers(Date.now() + 100)
123
+
124
+ const event2 = hlc.tick()
125
+
126
+ // Simulate receiving a message from another node
127
+ hlc.receive(`${Date.now() - 50}:5:remote-id`)
128
+
129
+ const event3 = hlc.tick()
130
+
131
+ // Advance time significantly
132
+ clock.tick(1000)
133
+
134
+ const event4 = hlc.tick()
135
+
136
+ // Clean up the fake timer
137
+ clock.restore()
138
+
139
+ // Parse all events
140
+ const parsedEvent1 = hlc.parse(event1)
141
+ const parsedEvent2 = hlc.parse(event2)
142
+ const parsedEvent3 = hlc.parse(event3)
143
+ const parsedEvent4 = hlc.parse(event4)
144
+
145
+ // Assertions to ensure causal order is maintained
146
+ expect(parsedEvent2.walltime).to.be.greaterThan(parsedEvent1.walltime)
147
+ expect(parsedEvent3.walltime).to.equal(parsedEvent2.walltime)
148
+ expect(parsedEvent3.nn).to.be.greaterThan(parsedEvent2.nn)
149
+ expect(parsedEvent4.walltime).to.be.greaterThan(parsedEvent3.walltime)
150
+
151
+ // Check that all events have the same id
152
+ const uniqueIds = new Set([
153
+ parsedEvent1.id,
154
+ parsedEvent2.id,
155
+ parsedEvent3.id,
156
+ parsedEvent4.id,
157
+ ])
158
+ expect(uniqueIds.size).to.equal(1)
159
+
160
+ // Ensure we can compare events as strings and maintain the same order
161
+ const events = [event1, event2, event3, event4]
162
+ const sortedEvents = [...events].sort()
163
+ expect(sortedEvents).to.deep.equal(events)
164
+ })
165
+ })