umap-project 2.6.2__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.
- umap/__init__.py +1 -1
- umap/admin.py +64 -1
- umap/asgi.py +15 -0
- umap/context_processors.py +1 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +96 -92
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +19 -18
- umap/locale/en/LC_MESSAGES/django.po +47 -43
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +134 -128
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +51 -47
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +64 -60
- umap/management/commands/clean_tilelayer.py +152 -0
- umap/management/commands/purge_purgatory.py +28 -0
- umap/models.py +27 -2
- umap/settings/base.py +3 -1
- umap/static/umap/base.css +4 -4
- umap/static/umap/css/contextmenu.css +6 -1
- umap/static/umap/css/icon.css +7 -2
- umap/static/umap/css/importers.css +4 -0
- umap/static/umap/img/16-white.svg +9 -2
- umap/static/umap/img/16.svg +1 -181
- umap/static/umap/img/24-white.svg +1 -0
- umap/static/umap/img/24.svg +1 -0
- umap/static/umap/img/importers/cadastrefr.svg +23 -0
- umap/static/umap/img/source/16-white.svg +10 -3
- umap/static/umap/img/source/16.svg +753 -197
- umap/static/umap/img/source/24-white.svg +3 -2
- umap/static/umap/img/source/24.svg +3 -2
- umap/static/umap/js/modules/autocomplete.js +7 -3
- umap/static/umap/js/modules/browser.js +55 -2
- umap/static/umap/js/modules/caption.js +16 -5
- umap/static/umap/js/modules/data/features.js +183 -8
- umap/static/umap/js/modules/data/layer.js +57 -40
- umap/static/umap/js/modules/formatter.js +3 -2
- umap/static/umap/js/modules/global.js +2 -0
- umap/static/umap/js/modules/importer.js +3 -0
- umap/static/umap/js/modules/importers/cadastrefr.js +62 -0
- umap/static/umap/js/modules/importers/communesfr.js +15 -3
- umap/static/umap/js/modules/permissions.js +123 -93
- umap/static/umap/js/modules/rendering/layers/classified.js +2 -0
- umap/static/umap/js/modules/rendering/ui.js +60 -213
- umap/static/umap/js/modules/share.js +1 -3
- umap/static/umap/js/modules/slideshow.js +1 -1
- umap/static/umap/js/modules/sync/engine.js +371 -14
- umap/static/umap/js/modules/sync/hlc.js +106 -0
- umap/static/umap/js/modules/sync/updaters.js +18 -6
- umap/static/umap/js/modules/sync/websocket.js +1 -1
- umap/static/umap/js/modules/tableeditor.js +1 -1
- umap/static/umap/js/modules/ui/base.js +2 -2
- umap/static/umap/js/modules/ui/contextmenu.js +51 -18
- umap/static/umap/js/modules/urls.js +5 -1
- umap/static/umap/js/modules/utils.js +28 -4
- umap/static/umap/js/umap.controls.js +76 -55
- umap/static/umap/js/umap.core.js +3 -3
- umap/static/umap/js/umap.forms.js +3 -1
- umap/static/umap/js/umap.js +115 -124
- umap/static/umap/locale/am_ET.js +2 -2
- umap/static/umap/locale/am_ET.json +2 -2
- umap/static/umap/locale/ar.js +2 -2
- umap/static/umap/locale/ar.json +2 -2
- umap/static/umap/locale/ast.js +2 -2
- umap/static/umap/locale/ast.json +2 -2
- umap/static/umap/locale/bg.js +2 -2
- umap/static/umap/locale/bg.json +2 -2
- umap/static/umap/locale/br.js +13 -4
- umap/static/umap/locale/br.json +13 -4
- umap/static/umap/locale/ca.js +30 -17
- umap/static/umap/locale/ca.json +30 -17
- umap/static/umap/locale/cs_CZ.js +89 -80
- umap/static/umap/locale/cs_CZ.json +89 -80
- umap/static/umap/locale/da.js +2 -2
- umap/static/umap/locale/da.json +2 -2
- umap/static/umap/locale/de.js +17 -8
- umap/static/umap/locale/de.json +17 -8
- umap/static/umap/locale/el.js +2 -2
- umap/static/umap/locale/el.json +2 -2
- umap/static/umap/locale/en.js +15 -4
- umap/static/umap/locale/en.json +15 -4
- umap/static/umap/locale/en_US.json +2 -2
- umap/static/umap/locale/es.js +338 -325
- umap/static/umap/locale/es.json +338 -325
- umap/static/umap/locale/et.js +2 -2
- umap/static/umap/locale/et.json +2 -2
- umap/static/umap/locale/eu.js +11 -4
- umap/static/umap/locale/eu.json +11 -4
- umap/static/umap/locale/fa_IR.js +11 -4
- umap/static/umap/locale/fa_IR.json +11 -4
- umap/static/umap/locale/fi.js +2 -2
- umap/static/umap/locale/fi.json +2 -2
- umap/static/umap/locale/fr.js +15 -4
- umap/static/umap/locale/fr.json +15 -4
- umap/static/umap/locale/gl.js +2 -2
- umap/static/umap/locale/gl.json +2 -2
- umap/static/umap/locale/he.js +2 -2
- umap/static/umap/locale/he.json +2 -2
- umap/static/umap/locale/hr.js +2 -2
- umap/static/umap/locale/hr.json +2 -2
- umap/static/umap/locale/hu.js +12 -5
- umap/static/umap/locale/hu.json +12 -5
- umap/static/umap/locale/id.js +2 -2
- umap/static/umap/locale/id.json +2 -2
- umap/static/umap/locale/is.js +2 -2
- umap/static/umap/locale/is.json +2 -2
- umap/static/umap/locale/it.js +2 -2
- umap/static/umap/locale/it.json +2 -2
- umap/static/umap/locale/ja.js +2 -2
- umap/static/umap/locale/ja.json +2 -2
- umap/static/umap/locale/ko.js +2 -2
- umap/static/umap/locale/ko.json +2 -2
- umap/static/umap/locale/lt.js +2 -2
- umap/static/umap/locale/lt.json +2 -2
- umap/static/umap/locale/ms.js +2 -2
- umap/static/umap/locale/ms.json +2 -2
- umap/static/umap/locale/nl.js +2 -2
- umap/static/umap/locale/nl.json +2 -2
- umap/static/umap/locale/no.js +2 -2
- umap/static/umap/locale/no.json +2 -2
- umap/static/umap/locale/pl.js +2 -2
- umap/static/umap/locale/pl.json +2 -2
- umap/static/umap/locale/pl_PL.json +2 -2
- umap/static/umap/locale/pt.js +19 -10
- umap/static/umap/locale/pt.json +19 -10
- umap/static/umap/locale/pt_BR.js +2 -2
- umap/static/umap/locale/pt_BR.json +2 -2
- umap/static/umap/locale/pt_PT.js +13 -4
- umap/static/umap/locale/pt_PT.json +13 -4
- umap/static/umap/locale/ro.js +2 -2
- umap/static/umap/locale/ro.json +2 -2
- umap/static/umap/locale/ru.js +2 -2
- umap/static/umap/locale/ru.json +2 -2
- umap/static/umap/locale/si.js +2 -2
- umap/static/umap/locale/si.json +2 -2
- umap/static/umap/locale/sk_SK.js +2 -2
- umap/static/umap/locale/sk_SK.json +2 -2
- umap/static/umap/locale/sl.js +2 -2
- umap/static/umap/locale/sl.json +2 -2
- umap/static/umap/locale/sr.js +2 -2
- umap/static/umap/locale/sr.json +2 -2
- umap/static/umap/locale/sv.js +2 -2
- umap/static/umap/locale/sv.json +2 -2
- umap/static/umap/locale/th_TH.js +2 -2
- umap/static/umap/locale/th_TH.json +2 -2
- umap/static/umap/locale/tr.js +2 -2
- umap/static/umap/locale/tr.json +2 -2
- umap/static/umap/locale/uk_UA.js +2 -2
- umap/static/umap/locale/uk_UA.json +2 -2
- umap/static/umap/locale/vi.js +2 -2
- umap/static/umap/locale/vi.json +2 -2
- umap/static/umap/locale/vi_VN.json +2 -2
- umap/static/umap/locale/zh.js +2 -2
- umap/static/umap/locale/zh.json +2 -2
- umap/static/umap/locale/zh_CN.json +2 -2
- umap/static/umap/locale/zh_TW.Big5.json +2 -2
- umap/static/umap/locale/zh_TW.js +13 -4
- umap/static/umap/locale/zh_TW.json +13 -4
- umap/static/umap/map.css +44 -29
- umap/static/umap/unittests/hlc.js +165 -0
- umap/static/umap/unittests/sync.js +321 -15
- umap/static/umap/unittests/utils.js +47 -0
- umap/static/umap/vars.css +2 -1
- umap/static/umap/vendors/colorbrewer/colorbrewer.js +309 -317
- umap/static/umap/vendors/dompurify/purify.es.js +15 -16
- umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
- umap/static/umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js +111 -80
- umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +2 -2
- umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +1 -1
- umap/static/umap/vendors/simple-statistics/simple-statistics.min.js +1 -1
- umap/static/umap/vendors/simple-statistics/simple-statistics.min.js.map +1 -1
- umap/templates/umap/css.html +0 -2
- umap/templates/umap/dashboard_menu.html +4 -2
- umap/templates/umap/js.html +0 -5
- umap/templates/umap/map_detail.html +2 -2
- umap/tests/fixtures/test_upload_data.csv +2 -2
- umap/tests/integration/test_anonymous_owned_map.py +1 -0
- umap/tests/integration/test_basics.py +1 -1
- umap/tests/integration/test_browser.py +69 -7
- umap/tests/integration/test_caption.py +3 -3
- umap/tests/integration/test_circles_layer.py +12 -0
- umap/tests/integration/test_cluster.py +53 -0
- umap/tests/integration/test_datalayer.py +2 -1
- umap/tests/integration/test_draw_polygon.py +17 -9
- umap/tests/integration/test_draw_polyline.py +84 -7
- umap/tests/integration/test_edit_datalayer.py +5 -8
- umap/tests/integration/test_edit_map.py +2 -2
- umap/tests/integration/test_edit_marker.py +1 -1
- umap/tests/integration/test_facets_browser.py +3 -3
- umap/tests/integration/test_import.py +1 -0
- umap/tests/integration/test_map.py +1 -0
- umap/tests/integration/test_owned_map.py +1 -1
- umap/tests/integration/test_view_marker.py +63 -0
- umap/tests/integration/test_view_polygon.py +12 -12
- umap/tests/integration/test_websocket_sync.py +65 -3
- umap/tests/test_clean_tilelayer.py +83 -0
- umap/tests/test_datalayer.py +24 -0
- umap/tests/test_map_views.py +20 -0
- umap/tests/test_purge_purgatory.py +25 -0
- umap/tests/test_websocket_server.py +22 -0
- umap/urls.py +5 -1
- umap/views.py +6 -3
- umap/websocket_server.py +130 -27
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/METADATA +18 -14
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/RECORD +209 -200
- umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.css +0 -1
- umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.js +0 -7
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/WHEEL +0 -0
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/entry_points.txt +0 -0
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,10 +5,10 @@ import pkg from 'chai'
|
|
|
5
5
|
const { expect } = pkg
|
|
6
6
|
|
|
7
7
|
import { MapUpdater } from '../js/modules/sync/updaters.js'
|
|
8
|
-
import { SyncEngine } from '../js/modules/sync/engine.js'
|
|
8
|
+
import { SyncEngine, Operations } from '../js/modules/sync/engine.js'
|
|
9
9
|
|
|
10
10
|
describe('SyncEngine', () => {
|
|
11
|
-
it('should initialize methods even before start',
|
|
11
|
+
it('should initialize methods even before start', () => {
|
|
12
12
|
const engine = new SyncEngine({})
|
|
13
13
|
engine.upsert()
|
|
14
14
|
engine.update()
|
|
@@ -16,8 +16,8 @@ describe('SyncEngine', () => {
|
|
|
16
16
|
})
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
describe('#dispatch',
|
|
20
|
-
it('should raise an error on unknown updater',
|
|
19
|
+
describe('#dispatch', () => {
|
|
20
|
+
it('should raise an error on unknown updater', () => {
|
|
21
21
|
const dispatcher = new SyncEngine({})
|
|
22
22
|
expect(() => {
|
|
23
23
|
dispatcher.dispatch({
|
|
@@ -27,7 +27,7 @@ describe('#dispatch', function () {
|
|
|
27
27
|
})
|
|
28
28
|
}).to.throw(Error)
|
|
29
29
|
})
|
|
30
|
-
it('should produce an error on malformated messages',
|
|
30
|
+
it('should produce an error on malformated messages', () => {
|
|
31
31
|
const dispatcher = new SyncEngine({})
|
|
32
32
|
expect(() => {
|
|
33
33
|
dispatcher.dispatch({
|
|
@@ -36,7 +36,7 @@ describe('#dispatch', function () {
|
|
|
36
36
|
})
|
|
37
37
|
}).to.throw(Error)
|
|
38
38
|
})
|
|
39
|
-
it('should raise an unknown operations',
|
|
39
|
+
it('should raise an unknown operations', () => {
|
|
40
40
|
const dispatcher = new SyncEngine({})
|
|
41
41
|
expect(() => {
|
|
42
42
|
dispatcher.dispatch({
|
|
@@ -47,55 +47,55 @@ describe('#dispatch', function () {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
describe('Updaters', () => {
|
|
50
|
-
describe('BaseUpdater',
|
|
50
|
+
describe('BaseUpdater', () => {
|
|
51
51
|
let updater
|
|
52
52
|
let map
|
|
53
53
|
let obj
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
beforeEach(() => {
|
|
56
56
|
map = {}
|
|
57
57
|
updater = new MapUpdater(map)
|
|
58
58
|
obj = {}
|
|
59
59
|
})
|
|
60
|
-
it('should be able to set object properties',
|
|
60
|
+
it('should be able to set object properties', () => {
|
|
61
61
|
let obj = {}
|
|
62
62
|
updater.updateObjectValue(obj, 'foo', 'foo')
|
|
63
63
|
expect(obj).deep.equal({ foo: 'foo' })
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
it('should be able to set object properties recursively on existing objects',
|
|
66
|
+
it('should be able to set object properties recursively on existing objects', () => {
|
|
67
67
|
let obj = { foo: {} }
|
|
68
68
|
updater.updateObjectValue(obj, 'foo.bar', 'foo')
|
|
69
69
|
expect(obj).deep.equal({ foo: { bar: 'foo' } })
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
it('should be able to set object properties recursively on deep objects',
|
|
72
|
+
it('should be able to set object properties recursively on deep objects', () => {
|
|
73
73
|
let obj = { foo: { bar: { baz: {} } } }
|
|
74
74
|
updater.updateObjectValue(obj, 'foo.bar.baz.test', 'value')
|
|
75
75
|
expect(obj).deep.equal({ foo: { bar: { baz: { test: 'value' } } } })
|
|
76
76
|
})
|
|
77
77
|
|
|
78
|
-
it('should be able to replace object properties recursively on deep objects',
|
|
78
|
+
it('should be able to replace object properties recursively on deep objects', () => {
|
|
79
79
|
let obj = { foo: { bar: { baz: { test: 'test' } } } }
|
|
80
80
|
updater.updateObjectValue(obj, 'foo.bar.baz.test', 'value')
|
|
81
81
|
expect(obj).deep.equal({ foo: { bar: { baz: { test: 'value' } } } })
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
it('should not set object properties recursively on non-existing objects',
|
|
84
|
+
it('should not set object properties recursively on non-existing objects', () => {
|
|
85
85
|
let obj = { foo: {} }
|
|
86
86
|
updater.updateObjectValue(obj, 'bar.bar', 'value')
|
|
87
87
|
|
|
88
88
|
expect(obj).deep.equal({ foo: {} })
|
|
89
89
|
})
|
|
90
90
|
|
|
91
|
-
it('should delete keys for undefined values',
|
|
91
|
+
it('should delete keys for undefined values', () => {
|
|
92
92
|
let obj = { foo: 'foo' }
|
|
93
93
|
updater.updateObjectValue(obj, 'foo', undefined)
|
|
94
94
|
|
|
95
95
|
expect(obj).deep.equal({})
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
-
it('should delete keys for undefined values, recursively',
|
|
98
|
+
it('should delete keys for undefined values, recursively', () => {
|
|
99
99
|
let obj = { foo: { bar: 'bar' } }
|
|
100
100
|
updater.updateObjectValue(obj, 'foo.bar', undefined)
|
|
101
101
|
|
|
@@ -103,3 +103,309 @@ describe('Updaters', () => {
|
|
|
103
103
|
})
|
|
104
104
|
})
|
|
105
105
|
})
|
|
106
|
+
|
|
107
|
+
describe('Operations', () => {
|
|
108
|
+
describe('haveSameContext', () => {
|
|
109
|
+
const createOperation = (overrides = {}) => ({
|
|
110
|
+
subject: 'feature',
|
|
111
|
+
metadata: {
|
|
112
|
+
id: 'UxNjQ',
|
|
113
|
+
layerId: '606d26bd-230f-4d3e-a2a7-0c3caed71548',
|
|
114
|
+
featureType: 'marker',
|
|
115
|
+
},
|
|
116
|
+
...overrides,
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('should check if subject and metadata are the same', () => {
|
|
120
|
+
const op1 = createOperation()
|
|
121
|
+
const op2 = createOperation()
|
|
122
|
+
const op3 = createOperation({
|
|
123
|
+
subject: 'datalayer',
|
|
124
|
+
metadata: { id: '606d26bd-230f-4d3e-a2a7-0c3caed71548' },
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
expect(Operations.haveSameContext(op1, op2)).to.be.true
|
|
128
|
+
expect(Operations.haveSameContext(op1, op3)).to.be.false
|
|
129
|
+
expect(Operations.haveSameContext(op2, op3)).to.be.false
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('should check if the key matches if there is any provided', () => {
|
|
133
|
+
const op1 = createOperation({ key: 'properties.name' })
|
|
134
|
+
const op2 = createOperation({ key: 'properties.name' })
|
|
135
|
+
const op3 = createOperation({ key: 'geometry' })
|
|
136
|
+
const op4 = createOperation()
|
|
137
|
+
|
|
138
|
+
expect(Operations.haveSameContext(op1, op2)).to.be.true
|
|
139
|
+
expect(Operations.haveSameContext(op1, op3)).to.be.false
|
|
140
|
+
expect(Operations.haveSameContext(op1, op4)).to.be.true
|
|
141
|
+
expect(Operations.haveSameContext(op4, createOperation())).to.be.true
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('should use deep equality for subject and metadata', () => {
|
|
145
|
+
const op1 = createOperation({ metadata: { nested: { value: 1 } } })
|
|
146
|
+
const op2 = createOperation({ metadata: { nested: { value: 1 } } })
|
|
147
|
+
const op3 = createOperation({ metadata: { nested: { value: 2 } } })
|
|
148
|
+
|
|
149
|
+
expect(Operations.haveSameContext(op1, op2)).to.be.true
|
|
150
|
+
expect(Operations.haveSameContext(op1, op3)).to.be.false
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
describe('sort', () => {
|
|
155
|
+
it('should sort operations by timestamp', () => {
|
|
156
|
+
const operations = [
|
|
157
|
+
{ hlc: '1727193550:44:id1' },
|
|
158
|
+
{ hlc: '1727193549:42:id1' },
|
|
159
|
+
{ hlc: '1727193551:43:id1' },
|
|
160
|
+
]
|
|
161
|
+
const sorted = Operations.sort(operations)
|
|
162
|
+
expect(sorted).to.deep.equal([
|
|
163
|
+
{ hlc: '1727193549:42:id1' },
|
|
164
|
+
{ hlc: '1727193550:44:id1' },
|
|
165
|
+
{ hlc: '1727193551:43:id1' },
|
|
166
|
+
])
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('should sort operations by NN when timestamp is the same', () => {
|
|
170
|
+
const operations = [
|
|
171
|
+
{ hlc: '1727193549:42:id1' },
|
|
172
|
+
{ hlc: '1727193549:44:id1' },
|
|
173
|
+
{ hlc: '1727193549:43:id1' },
|
|
174
|
+
]
|
|
175
|
+
const sorted = Operations.sort(operations)
|
|
176
|
+
expect(sorted).to.deep.equal([
|
|
177
|
+
{ hlc: '1727193549:42:id1' },
|
|
178
|
+
{ hlc: '1727193549:43:id1' },
|
|
179
|
+
{ hlc: '1727193549:44:id1' },
|
|
180
|
+
])
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('should sort operations by id if other fields are equal', () => {
|
|
184
|
+
const operations = [
|
|
185
|
+
{ hlc: '1727193549:42:id3' },
|
|
186
|
+
{ hlc: '1727193549:42:id2' },
|
|
187
|
+
{ hlc: '1727193549:42:id1' },
|
|
188
|
+
]
|
|
189
|
+
const sorted = Operations.sort(operations)
|
|
190
|
+
expect(sorted).to.deep.equal([
|
|
191
|
+
{ hlc: '1727193549:42:id1' },
|
|
192
|
+
{ hlc: '1727193549:42:id2' },
|
|
193
|
+
{ hlc: '1727193549:42:id3' },
|
|
194
|
+
])
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
describe('addLocal', () => {
|
|
199
|
+
it('should add a local operation with a new hlc', () => {
|
|
200
|
+
const ops = new Operations()
|
|
201
|
+
const inputMessage = { verb: 'update', subject: 'test' }
|
|
202
|
+
const result = ops.addLocal(inputMessage)
|
|
203
|
+
expect(result).to.have.property('hlc')
|
|
204
|
+
expect(result.hlc).to.match(/^\d+:\d+:[^:]+$/)
|
|
205
|
+
expect(result).to.include(inputMessage)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
describe('sorted', () => {
|
|
210
|
+
it('should return sorted operations', () => {
|
|
211
|
+
const ops = new Operations()
|
|
212
|
+
ops._operations = [{ hlc: '1727193549:43:id1' }, { hlc: '1727193549:42:id1' }]
|
|
213
|
+
const sorted = ops.sorted()
|
|
214
|
+
expect(sorted[0].hlc).to.equal('1727193549:42:id1')
|
|
215
|
+
expect(sorted[1].hlc).to.equal('1727193549:43:id1')
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe('shouldBypassOperation', () => {
|
|
220
|
+
let ops
|
|
221
|
+
|
|
222
|
+
beforeEach(() => {
|
|
223
|
+
ops = new Operations()
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const createOperation = (overrides = {}) => ({
|
|
227
|
+
verb: 'update',
|
|
228
|
+
subject: 'feature',
|
|
229
|
+
metadata: {
|
|
230
|
+
id: 'UxNjQ',
|
|
231
|
+
layerId: '606d26bd-230f-4d3e-a2a7-0c3caed71548',
|
|
232
|
+
featureType: 'marker',
|
|
233
|
+
},
|
|
234
|
+
key: 'properties.name',
|
|
235
|
+
value: 'default',
|
|
236
|
+
hlc: '0000000000000:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
237
|
+
...overrides,
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const createUpsertOperation = (overrides = {}) =>
|
|
241
|
+
createOperation({
|
|
242
|
+
verb: 'upsert',
|
|
243
|
+
key: undefined,
|
|
244
|
+
value: {
|
|
245
|
+
type: 'Feature',
|
|
246
|
+
geometry: {
|
|
247
|
+
coordinates: [0.439453, 48.04871],
|
|
248
|
+
type: 'Point',
|
|
249
|
+
},
|
|
250
|
+
properties: {},
|
|
251
|
+
id: 'UxNjQ',
|
|
252
|
+
},
|
|
253
|
+
...overrides,
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('should return false if no local operation is newer', () => {
|
|
257
|
+
const remote = createUpsertOperation({ hlc: '1727184449050:44:id2' })
|
|
258
|
+
ops._operations = [
|
|
259
|
+
createOperation({
|
|
260
|
+
hlc: '1727184449010:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
261
|
+
}),
|
|
262
|
+
createUpsertOperation({
|
|
263
|
+
hlc: '1727184449020:0:b4a221a0-7b62-4588-a6af-041b041006dc',
|
|
264
|
+
}),
|
|
265
|
+
]
|
|
266
|
+
|
|
267
|
+
const result = ops.shouldBypassOperation(remote)
|
|
268
|
+
expect(result).to.be.false
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('should return true if a similar "delete" operation is newer', () => {
|
|
272
|
+
const remote = createOperation({
|
|
273
|
+
verb: 'delete',
|
|
274
|
+
metadata: { id: 'M1NTA', layerId: '1234', featureType: 'marker' },
|
|
275
|
+
hlc: '1:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
ops._operations = [
|
|
279
|
+
createOperation({
|
|
280
|
+
verb: 'delete',
|
|
281
|
+
metadata: { id: 'M1NTA', layerId: '1234', featureType: 'marker' },
|
|
282
|
+
hlc: '2:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
283
|
+
}),
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
const result = ops.shouldBypassOperation(remote)
|
|
287
|
+
expect(result).to.be.true
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
describe('update', () => {
|
|
291
|
+
it('should check for related updates', () => {
|
|
292
|
+
ops._operations = [
|
|
293
|
+
createOperation({
|
|
294
|
+
value: 'y',
|
|
295
|
+
hlc: '1:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
296
|
+
}),
|
|
297
|
+
createOperation({
|
|
298
|
+
value: 'youpi',
|
|
299
|
+
hlc: '9:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
300
|
+
}),
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
const remoteOperation = createOperation({
|
|
304
|
+
value: 'something else',
|
|
305
|
+
hlc: '0:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const result = ops.shouldBypassOperation(remoteOperation)
|
|
309
|
+
expect(result).to.be.true
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
it('should check for related deletes', () => {
|
|
313
|
+
ops._operations = [
|
|
314
|
+
{
|
|
315
|
+
verb: 'delete',
|
|
316
|
+
subject: 'feature',
|
|
317
|
+
metadata: {
|
|
318
|
+
id: 'M1NTA',
|
|
319
|
+
layerId: '123',
|
|
320
|
+
featureType: 'marker',
|
|
321
|
+
},
|
|
322
|
+
hlc: '1727196583562:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
323
|
+
key: undefined,
|
|
324
|
+
},
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
const remoteOperation = createOperation({
|
|
328
|
+
metadata: { id: 'M1NTA', layerId: '123', featureType: 'marker' },
|
|
329
|
+
key: 'geometry',
|
|
330
|
+
value: { coordinates: [2.944336, 47.070122], type: 'Point' },
|
|
331
|
+
hlc: '0:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const result = ops.shouldBypassOperation(remoteOperation)
|
|
335
|
+
expect(result).to.be.true
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
describe('upsert', () => {
|
|
340
|
+
it('should take precedence over updates (even if fresher)', () => {
|
|
341
|
+
ops._operations = [
|
|
342
|
+
createOperation({
|
|
343
|
+
value: 'youpi',
|
|
344
|
+
hlc: '1000000000000:0:f4df51cc-7617-4bd4-8bd2-599cdf17da65',
|
|
345
|
+
}),
|
|
346
|
+
]
|
|
347
|
+
|
|
348
|
+
const remoteOperation = createUpsertOperation({
|
|
349
|
+
hlc: '0000000000000:0:b4a221a0-7b62-4588-a6af-041b041006dc',
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
const result = ops.shouldBypassOperation(remoteOperation)
|
|
353
|
+
expect(result).to.be.false
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
describe('delete', () => {
|
|
358
|
+
it('should check for the same delete', () => {
|
|
359
|
+
ops._operations = [
|
|
360
|
+
createOperation({
|
|
361
|
+
verb: 'delete',
|
|
362
|
+
metadata: { id: 'I3MDg', layerId: null, featureType: 'polygon' },
|
|
363
|
+
key: undefined,
|
|
364
|
+
hlc: '1:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
365
|
+
}),
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
const remoteOperation = createOperation({
|
|
369
|
+
verb: 'delete',
|
|
370
|
+
metadata: { id: 'I3MDg', layerId: null, featureType: 'polygon' },
|
|
371
|
+
key: undefined,
|
|
372
|
+
hlc: '0:0:3f45b56f-f750-4b50-90d7-9ecce4b0cf53',
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
const result = ops.shouldBypassOperation(remoteOperation)
|
|
376
|
+
expect(result).to.be.true
|
|
377
|
+
})
|
|
378
|
+
})
|
|
379
|
+
})
|
|
380
|
+
describe('storeRemoteOperations', () => {
|
|
381
|
+
it('should store remote operations and update the local HLC', () => {
|
|
382
|
+
const ops = new Operations()
|
|
383
|
+
const remoteOps = [{ hlc: '1727193549:42:id2' }, { hlc: '1727193549:43:id2' }]
|
|
384
|
+
ops.storeRemoteOperations(remoteOps)
|
|
385
|
+
expect(ops._operations).to.deep.equal(remoteOps)
|
|
386
|
+
})
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
describe('getOperationsSince', () => {
|
|
390
|
+
it('should return operations since a given HLC', () => {
|
|
391
|
+
const ops = new Operations()
|
|
392
|
+
ops._operations = [
|
|
393
|
+
{ hlc: '1727193549:42:id1' },
|
|
394
|
+
{ hlc: '1727193549:43:id1' },
|
|
395
|
+
{ hlc: '1727193549:44:id1' },
|
|
396
|
+
]
|
|
397
|
+
const result = ops.getOperationsSince('1727193549:42:id1')
|
|
398
|
+
expect(result).to.deep.equal([
|
|
399
|
+
{ hlc: '1727193549:43:id1' },
|
|
400
|
+
{ hlc: '1727193549:44:id1' },
|
|
401
|
+
])
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('should return all operations if no HLC is provided', () => {
|
|
405
|
+
const ops = new Operations()
|
|
406
|
+
ops._operations = [{ hlc: '1727193549:42:id1' }, { hlc: '1727193549:43:id1' }]
|
|
407
|
+
const result = ops.getOperationsSince()
|
|
408
|
+
expect(result).to.deep.equal(ops._operations)
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
})
|
|
@@ -747,6 +747,30 @@ describe('Utils', () => {
|
|
|
747
747
|
})
|
|
748
748
|
})
|
|
749
749
|
|
|
750
|
+
describe('#fieldInSchema', () => {
|
|
751
|
+
it('should return true if the field is in the schema', () => {
|
|
752
|
+
assert.equal(Utils.fieldInSchema('foo', { foo: {} }), true)
|
|
753
|
+
})
|
|
754
|
+
it('should return false if the field is not in the schema', () => {
|
|
755
|
+
assert.equal(Utils.fieldInSchema('foo', { bar: {} }), false)
|
|
756
|
+
})
|
|
757
|
+
it('should return false if the schema is not provided', () => {
|
|
758
|
+
assert.equal(Utils.fieldInSchema('foo', {}), false)
|
|
759
|
+
})
|
|
760
|
+
it('should return false if the field is undefined', () => {
|
|
761
|
+
assert.equal(Utils.fieldInSchema(undefined, {}), false)
|
|
762
|
+
})
|
|
763
|
+
// check that options. is removed
|
|
764
|
+
it('should remove options. from the field', () => {
|
|
765
|
+
assert.equal(Utils.fieldInSchema('options.foo', { foo: {} }), true)
|
|
766
|
+
})
|
|
767
|
+
|
|
768
|
+
// check that subfields are removed
|
|
769
|
+
it('should remove subfields from the field', () => {
|
|
770
|
+
assert.equal(Utils.fieldInSchema('options.foo.bar', { foo: { bar: {} } }), true)
|
|
771
|
+
})
|
|
772
|
+
})
|
|
773
|
+
|
|
750
774
|
describe('#parseNaiveDate', () => {
|
|
751
775
|
it('should parse a date', () => {
|
|
752
776
|
assert.equal(
|
|
@@ -779,4 +803,27 @@ describe('Utils', () => {
|
|
|
779
803
|
)
|
|
780
804
|
})
|
|
781
805
|
})
|
|
806
|
+
|
|
807
|
+
describe('#isObject', () => {
|
|
808
|
+
it('should return true for objects', () => {
|
|
809
|
+
assert.equal(Utils.isObject({}), true)
|
|
810
|
+
assert.equal(Utils.isObject({ foo: 'bar' }), true)
|
|
811
|
+
})
|
|
812
|
+
|
|
813
|
+
it('should return false for Array', () => {
|
|
814
|
+
assert.equal(Utils.isObject([]), false)
|
|
815
|
+
})
|
|
816
|
+
|
|
817
|
+
it('should return false on null', () => {
|
|
818
|
+
assert.equal(Utils.isObject(null), false)
|
|
819
|
+
})
|
|
820
|
+
|
|
821
|
+
it('should return false on undefined', () => {
|
|
822
|
+
assert.equal(Utils.isObject(undefined), false)
|
|
823
|
+
})
|
|
824
|
+
|
|
825
|
+
it('should return false on string', () => {
|
|
826
|
+
assert.equal(Utils.isObject(''), false)
|
|
827
|
+
})
|
|
828
|
+
})
|
|
782
829
|
})
|
umap/static/umap/vars.css
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
--color-mediumGray: #3e4444;
|
|
7
7
|
--color-darkGray: #323737;
|
|
8
8
|
--color-light: white;
|
|
9
|
+
--color-dark: black;
|
|
9
10
|
--color-limeGreen: #b9f5d2;
|
|
10
11
|
--color-brightCyan: #46ece6;
|
|
11
12
|
--color-lightCyan: #d4fbf9;
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
|
|
15
16
|
--background-color: var(--color-light);
|
|
16
17
|
--color-accent: var(--color-brightCyan);
|
|
17
|
-
--text-color:
|
|
18
|
+
--text-color: var(--color-dark);
|
|
18
19
|
|
|
19
20
|
/* Buttons. */
|
|
20
21
|
--button-primary-background: var(--color-waterMint);
|