umap-project 3.1.2__py3-none-any.whl → 3.2.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/locale/en/LC_MESSAGES/django.po +21 -17
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +21 -17
- umap/management/commands/export_pictogram.py +29 -0
- umap/management/commands/migrate_to_S3.py +5 -1
- umap/management/commands/purge_old_versions.py +8 -6
- umap/settings/__init__.py +21 -0
- umap/settings/base.py +1 -0
- umap/static/umap/content.css +7 -2
- umap/static/umap/css/icon.css +77 -3
- umap/static/umap/css/panel.css +31 -1
- umap/static/umap/js/modules/browser.js +1 -1
- umap/static/umap/js/modules/data/features.js +14 -29
- umap/static/umap/js/modules/data/layer.js +248 -136
- umap/static/umap/js/modules/facets.js +2 -2
- umap/static/umap/js/modules/form/fields.js +56 -19
- umap/static/umap/js/modules/formatter.js +36 -8
- umap/static/umap/js/modules/importers/opendata.js +23 -6
- umap/static/umap/js/modules/managers.js +59 -0
- umap/static/umap/js/modules/rendering/icon.js +3 -5
- umap/static/umap/js/modules/rendering/layers/classified.js +8 -7
- umap/static/umap/js/modules/rendering/map.js +1 -1
- umap/static/umap/js/modules/rendering/ui.js +13 -0
- umap/static/umap/js/modules/rules.js +76 -23
- umap/static/umap/js/modules/schema.js +3 -0
- umap/static/umap/js/modules/slideshow.js +1 -1
- umap/static/umap/js/modules/sync/updaters.js +1 -6
- umap/static/umap/js/modules/tableeditor.js +13 -37
- umap/static/umap/js/modules/templates.js +7 -6
- umap/static/umap/js/modules/ui/panel.js +7 -0
- umap/static/umap/js/modules/umap.js +17 -6
- umap/static/umap/js/modules/utils.js +8 -7
- umap/static/umap/locale/am_ET.js +43 -6
- umap/static/umap/locale/am_ET.json +43 -6
- umap/static/umap/locale/ar.js +43 -6
- umap/static/umap/locale/ar.json +43 -6
- umap/static/umap/locale/ast.js +43 -6
- umap/static/umap/locale/ast.json +43 -6
- umap/static/umap/locale/bg.js +43 -6
- umap/static/umap/locale/bg.json +43 -6
- umap/static/umap/locale/br.js +30 -26
- umap/static/umap/locale/br.json +30 -26
- umap/static/umap/locale/ca.js +50 -13
- umap/static/umap/locale/ca.json +50 -13
- umap/static/umap/locale/cs_CZ.js +43 -6
- umap/static/umap/locale/cs_CZ.json +43 -6
- umap/static/umap/locale/da.js +10 -6
- umap/static/umap/locale/da.json +10 -6
- umap/static/umap/locale/de.js +10 -6
- umap/static/umap/locale/de.json +10 -6
- umap/static/umap/locale/el.js +20 -10
- umap/static/umap/locale/el.json +20 -10
- umap/static/umap/locale/en.js +10 -6
- umap/static/umap/locale/en.json +10 -6
- umap/static/umap/locale/en_US.json +43 -6
- umap/static/umap/locale/es.js +10 -6
- umap/static/umap/locale/es.json +10 -6
- umap/static/umap/locale/et.js +43 -6
- umap/static/umap/locale/et.json +43 -6
- umap/static/umap/locale/eu.js +43 -6
- umap/static/umap/locale/eu.json +43 -6
- umap/static/umap/locale/fa_IR.js +43 -6
- umap/static/umap/locale/fa_IR.json +43 -6
- umap/static/umap/locale/fi.js +43 -6
- umap/static/umap/locale/fi.json +43 -6
- umap/static/umap/locale/fr.js +10 -6
- umap/static/umap/locale/fr.json +10 -6
- umap/static/umap/locale/gl.js +43 -6
- umap/static/umap/locale/gl.json +43 -6
- umap/static/umap/locale/he.js +43 -6
- umap/static/umap/locale/he.json +43 -6
- umap/static/umap/locale/hr.js +43 -6
- umap/static/umap/locale/hr.json +43 -6
- umap/static/umap/locale/hu.js +34 -24
- umap/static/umap/locale/hu.json +34 -24
- umap/static/umap/locale/id.js +43 -6
- umap/static/umap/locale/id.json +43 -6
- umap/static/umap/locale/is.js +43 -6
- umap/static/umap/locale/is.json +43 -6
- umap/static/umap/locale/it.js +10 -6
- umap/static/umap/locale/it.json +10 -6
- umap/static/umap/locale/ja.js +43 -6
- umap/static/umap/locale/ja.json +43 -6
- umap/static/umap/locale/ko.js +43 -6
- umap/static/umap/locale/ko.json +43 -6
- umap/static/umap/locale/lt.js +43 -6
- umap/static/umap/locale/lt.json +43 -6
- umap/static/umap/locale/ms.js +43 -6
- umap/static/umap/locale/ms.json +43 -6
- umap/static/umap/locale/nl.js +10 -6
- umap/static/umap/locale/nl.json +10 -6
- umap/static/umap/locale/no.js +43 -6
- umap/static/umap/locale/no.json +43 -6
- umap/static/umap/locale/pl.js +43 -6
- umap/static/umap/locale/pl.json +43 -6
- umap/static/umap/locale/pl_PL.json +43 -6
- umap/static/umap/locale/pt.js +43 -6
- umap/static/umap/locale/pt.json +43 -6
- umap/static/umap/locale/pt_BR.js +53 -16
- umap/static/umap/locale/pt_BR.json +53 -16
- umap/static/umap/locale/pt_PT.js +43 -6
- umap/static/umap/locale/pt_PT.json +43 -6
- umap/static/umap/locale/ro.js +43 -6
- umap/static/umap/locale/ro.json +43 -6
- umap/static/umap/locale/ru.js +43 -6
- umap/static/umap/locale/ru.json +43 -6
- umap/static/umap/locale/sk_SK.js +43 -6
- umap/static/umap/locale/sk_SK.json +43 -6
- umap/static/umap/locale/sl.js +43 -6
- umap/static/umap/locale/sl.json +43 -6
- umap/static/umap/locale/sr.js +43 -6
- umap/static/umap/locale/sr.json +43 -6
- umap/static/umap/locale/sv.js +43 -6
- umap/static/umap/locale/sv.json +43 -6
- umap/static/umap/locale/th_TH.js +43 -6
- umap/static/umap/locale/th_TH.json +43 -6
- umap/static/umap/locale/tr.js +43 -6
- umap/static/umap/locale/tr.json +43 -6
- umap/static/umap/locale/uk_UA.js +43 -6
- umap/static/umap/locale/uk_UA.json +43 -6
- umap/static/umap/locale/vi.js +43 -6
- umap/static/umap/locale/vi.json +43 -6
- umap/static/umap/locale/vi_VN.json +43 -6
- umap/static/umap/locale/zh.js +43 -6
- umap/static/umap/locale/zh.json +43 -6
- umap/static/umap/locale/zh_CN.json +43 -6
- umap/static/umap/locale/zh_TW.Big5.json +43 -6
- umap/static/umap/locale/zh_TW.js +43 -6
- umap/static/umap/locale/zh_TW.json +43 -6
- umap/static/umap/map.css +239 -65
- umap/static/umap/vendors/betterknown/betterknown.mjs +287 -0
- umap/storage/fs.py +3 -2
- umap/templates/base.html +4 -1
- umap/tests/base.py +9 -1
- umap/tests/integration/test_basics.py +1 -1
- umap/tests/integration/test_conditional_rules.py +62 -20
- umap/tests/integration/test_edit_datalayer.py +1 -1
- umap/tests/integration/test_edit_marker.py +1 -1
- umap/tests/integration/test_export_map.py +10 -0
- umap/tests/integration/test_import.py +140 -0
- umap/tests/integration/test_optimistic_merge.py +72 -12
- umap/tests/integration/test_tableeditor.py +6 -3
- umap/utils.py +33 -0
- umap/views.py +16 -2
- umap_project-3.2.0.dist-info/METADATA +76 -0
- {umap_project-3.1.2.dist-info → umap_project-3.2.0.dist-info}/RECORD +150 -148
- umap_project-3.1.2.dist-info/METADATA +0 -68
- {umap_project-3.1.2.dist-info → umap_project-3.2.0.dist-info}/WHEEL +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.2.0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
var l = Object.defineProperty;
|
|
2
|
+
var d = (t, n, e) => n in t ? l(t, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[n] = e;
|
|
3
|
+
var p = (t, n, e) => (d(t, typeof n != "symbol" ? n + "" : n, e), e);
|
|
4
|
+
const M = [
|
|
5
|
+
"Point",
|
|
6
|
+
"LineString",
|
|
7
|
+
"Polygon",
|
|
8
|
+
"MultiPoint",
|
|
9
|
+
"MultiLineString",
|
|
10
|
+
"MultiPolygon",
|
|
11
|
+
"GeometryCollection"
|
|
12
|
+
], f = ["ZM", "Z", "M"], s = "EMPTY";
|
|
13
|
+
class G {
|
|
14
|
+
constructor(n) {
|
|
15
|
+
p(this, "value");
|
|
16
|
+
p(this, "position");
|
|
17
|
+
this.value = n.toUpperCase(), this.position = 0;
|
|
18
|
+
}
|
|
19
|
+
match(n) {
|
|
20
|
+
this.skipWhitespaces();
|
|
21
|
+
for (const e of n) {
|
|
22
|
+
const r = e.toUpperCase();
|
|
23
|
+
if (this.value.startsWith(r, this.position))
|
|
24
|
+
return this.position += r.length, e;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
matchRegex(n) {
|
|
29
|
+
this.skipWhitespaces();
|
|
30
|
+
for (const e of n) {
|
|
31
|
+
const r = this.value.substring(this.position).match(e);
|
|
32
|
+
if (r)
|
|
33
|
+
return this.position += r[0].length, r;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
isMatch(n) {
|
|
38
|
+
return this.skipWhitespaces(), this.value.startsWith(n, this.position) ? (this.position += n.length, !0) : !1;
|
|
39
|
+
}
|
|
40
|
+
matchType() {
|
|
41
|
+
const n = this.match(M);
|
|
42
|
+
if (!n)
|
|
43
|
+
throw new Error("Expected geometry type");
|
|
44
|
+
return n;
|
|
45
|
+
}
|
|
46
|
+
matchDimension() {
|
|
47
|
+
switch (this.match(f)) {
|
|
48
|
+
case "ZM":
|
|
49
|
+
return { hasZ: !0, hasM: !0 };
|
|
50
|
+
case "Z":
|
|
51
|
+
return { hasZ: !0, hasM: !1 };
|
|
52
|
+
case "M":
|
|
53
|
+
return { hasZ: !1, hasM: !0 };
|
|
54
|
+
default:
|
|
55
|
+
return { hasZ: !1, hasM: !1 };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
expectGroupStart() {
|
|
59
|
+
if (!this.isMatch("("))
|
|
60
|
+
throw new Error("Expected group start");
|
|
61
|
+
}
|
|
62
|
+
expectGroupEnd() {
|
|
63
|
+
if (!this.isMatch(")"))
|
|
64
|
+
throw new Error("Expected group end");
|
|
65
|
+
}
|
|
66
|
+
matchCoordinate(n) {
|
|
67
|
+
let e;
|
|
68
|
+
if (n.hasZ && n.hasM ? e = this.matchRegex([/^(\S*)\s+(\S*)\s+(\S*)\s+([^\s,)]*)/i]) : n.hasZ || n.hasM ? e = this.matchRegex([/^(\S*)\s+(\S*)\s+([^\s,)]*)/i]) : e = this.matchRegex([/^(\S*)\s+([^\s,)]*)/i]), !e)
|
|
69
|
+
throw new Error("Expected coordinates");
|
|
70
|
+
const r = n.hasZ && n.hasM ? [
|
|
71
|
+
parseFloat(e[1]),
|
|
72
|
+
parseFloat(e[2]),
|
|
73
|
+
parseFloat(e[3]),
|
|
74
|
+
parseFloat(e[4])
|
|
75
|
+
] : n.hasZ ? [parseFloat(e[1]), parseFloat(e[2]), parseFloat(e[3])] : n.hasM ? [
|
|
76
|
+
parseFloat(e[1]),
|
|
77
|
+
parseFloat(e[2])
|
|
78
|
+
] : [parseFloat(e[1]), parseFloat(e[2])];
|
|
79
|
+
if (n.srid && n.srid !== 4326) {
|
|
80
|
+
if (n.proj)
|
|
81
|
+
return n.proj(`EPSG:${n.srid}`, "EPSG:4326", r);
|
|
82
|
+
throw new Error(
|
|
83
|
+
`EWKT data in an unknown SRID (${n.srid}) was provided, but a proj function was not`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return r;
|
|
87
|
+
}
|
|
88
|
+
matchCoordinates(n) {
|
|
89
|
+
const e = [];
|
|
90
|
+
do {
|
|
91
|
+
const r = this.isMatch("(");
|
|
92
|
+
e.push(this.matchCoordinate(n)), r && this.expectGroupEnd();
|
|
93
|
+
} while (this.isMatch(","));
|
|
94
|
+
return e;
|
|
95
|
+
}
|
|
96
|
+
skipWhitespaces() {
|
|
97
|
+
for (; this.position < this.value.length && this.value[this.position] === " "; )
|
|
98
|
+
this.position++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const g = (t, n) => {
|
|
102
|
+
if (t.isMatch(s))
|
|
103
|
+
return n.emptyAsNull ? null : { type: "Point", coordinates: [] };
|
|
104
|
+
t.expectGroupStart();
|
|
105
|
+
const e = t.matchCoordinate(n);
|
|
106
|
+
return t.expectGroupEnd(), {
|
|
107
|
+
type: "Point",
|
|
108
|
+
coordinates: e
|
|
109
|
+
};
|
|
110
|
+
}, E = (t, n) => {
|
|
111
|
+
if (t.isMatch(s))
|
|
112
|
+
return n.emptyAsNull ? null : { type: "LineString", coordinates: [] };
|
|
113
|
+
t.expectGroupStart();
|
|
114
|
+
const e = t.matchCoordinates(n);
|
|
115
|
+
return t.expectGroupEnd(), {
|
|
116
|
+
type: "LineString",
|
|
117
|
+
coordinates: e
|
|
118
|
+
};
|
|
119
|
+
}, m = (t, n) => {
|
|
120
|
+
if (t.isMatch(s))
|
|
121
|
+
return n.emptyAsNull ? null : { type: "Polygon", coordinates: [] };
|
|
122
|
+
const e = [];
|
|
123
|
+
for (t.expectGroupStart(), t.expectGroupStart(), e.push(t.matchCoordinates(n)), t.expectGroupEnd(); t.isMatch(","); )
|
|
124
|
+
t.expectGroupStart(), e.push(t.matchCoordinates(n)), t.expectGroupEnd();
|
|
125
|
+
return t.expectGroupEnd(), {
|
|
126
|
+
type: "Polygon",
|
|
127
|
+
coordinates: e
|
|
128
|
+
};
|
|
129
|
+
}, S = (t, n) => {
|
|
130
|
+
if (t.isMatch(s))
|
|
131
|
+
return n.emptyAsNull ? null : { type: "MultiPoint", coordinates: [] };
|
|
132
|
+
t.expectGroupStart();
|
|
133
|
+
const e = t.matchCoordinates(n);
|
|
134
|
+
return t.expectGroupEnd(), {
|
|
135
|
+
type: "MultiPoint",
|
|
136
|
+
coordinates: e
|
|
137
|
+
};
|
|
138
|
+
}, y = (t, n) => {
|
|
139
|
+
if (t.isMatch(s))
|
|
140
|
+
return n.emptyAsNull ? null : { type: "MultiLineString", coordinates: [] };
|
|
141
|
+
t.expectGroupStart();
|
|
142
|
+
const e = [];
|
|
143
|
+
do
|
|
144
|
+
t.expectGroupStart(), e.push(t.matchCoordinates(n)), t.expectGroupEnd();
|
|
145
|
+
while (t.isMatch(","));
|
|
146
|
+
return t.expectGroupEnd(), {
|
|
147
|
+
type: "MultiLineString",
|
|
148
|
+
coordinates: e
|
|
149
|
+
};
|
|
150
|
+
}, x = (t, n) => {
|
|
151
|
+
if (t.isMatch(s))
|
|
152
|
+
return n.emptyAsNull ? null : { type: "MultiPolygon", coordinates: [] };
|
|
153
|
+
t.expectGroupStart();
|
|
154
|
+
const e = [];
|
|
155
|
+
do {
|
|
156
|
+
t.expectGroupStart();
|
|
157
|
+
const r = [], o = [];
|
|
158
|
+
for (t.expectGroupStart(), r.push.apply(r, t.matchCoordinates(n)), t.expectGroupEnd(); t.isMatch(","); )
|
|
159
|
+
t.expectGroupStart(), o.push(t.matchCoordinates(n)), t.expectGroupEnd();
|
|
160
|
+
e.push([r, ...o]), t.expectGroupEnd();
|
|
161
|
+
} while (t.isMatch(","));
|
|
162
|
+
return t.expectGroupEnd(), {
|
|
163
|
+
type: "MultiPolygon",
|
|
164
|
+
coordinates: e
|
|
165
|
+
};
|
|
166
|
+
}, P = (t, n) => {
|
|
167
|
+
if (t.isMatch(s))
|
|
168
|
+
return n.emptyAsNull ? null : { type: "GeometryCollection", geometries: [] };
|
|
169
|
+
t.expectGroupStart();
|
|
170
|
+
const e = [];
|
|
171
|
+
do {
|
|
172
|
+
const r = u(t, n);
|
|
173
|
+
r && e.push(r);
|
|
174
|
+
} while (t.isMatch(","));
|
|
175
|
+
return t.expectGroupEnd(), {
|
|
176
|
+
type: "GeometryCollection",
|
|
177
|
+
geometries: e
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
function c(t) {
|
|
181
|
+
return t.join(" ");
|
|
182
|
+
}
|
|
183
|
+
function a(t) {
|
|
184
|
+
if (t === void 0)
|
|
185
|
+
return " ";
|
|
186
|
+
switch (t.length) {
|
|
187
|
+
case 3:
|
|
188
|
+
return " Z ";
|
|
189
|
+
default:
|
|
190
|
+
return " ";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function T(t) {
|
|
194
|
+
return t.coordinates.length === 0 ? "POINT EMPTY" : `POINT${a(t.coordinates)}(${c(
|
|
195
|
+
t.coordinates
|
|
196
|
+
)})`;
|
|
197
|
+
}
|
|
198
|
+
function L(t) {
|
|
199
|
+
return t.coordinates.length === 0 ? "MULTIPOINT EMPTY" : `MULTIPOINT${a(
|
|
200
|
+
t.coordinates[0]
|
|
201
|
+
)}(${t.coordinates.map((n) => c(n)).join(",")})`;
|
|
202
|
+
}
|
|
203
|
+
function N(t) {
|
|
204
|
+
if (t.coordinates.length === 0)
|
|
205
|
+
return "LINESTRING EMPTY";
|
|
206
|
+
const n = `(${t.coordinates.map((e) => c(e)).join(",")})`;
|
|
207
|
+
return `LINESTRING${a(t.coordinates[0])}${n}`;
|
|
208
|
+
}
|
|
209
|
+
function C(t) {
|
|
210
|
+
return t.geometries.length === 0 ? "GEOMETRYCOLLECTION EMPTY" : `GEOMETRYCOLLECTION${`(${t.geometries.map((e) => O(e)).join(",")})`}`;
|
|
211
|
+
}
|
|
212
|
+
function I(t) {
|
|
213
|
+
if (t.coordinates.length === 0)
|
|
214
|
+
return "MULTILINESTRING EMPTY";
|
|
215
|
+
const n = `(${t.coordinates.map((e) => `(${e.map((r) => c(r))})`)})`;
|
|
216
|
+
return `MULTILINESTRING${a(t.coordinates[0][0])}${n}`;
|
|
217
|
+
}
|
|
218
|
+
function W(t) {
|
|
219
|
+
var e;
|
|
220
|
+
if (t.coordinates.length === 0)
|
|
221
|
+
return "POLYGON EMPTY";
|
|
222
|
+
const n = `(${t.coordinates.map((r) => `(${r.map((o) => c(o))})`)})`;
|
|
223
|
+
return `POLYGON${a((e = t.coordinates[0]) == null ? void 0 : e[0])}${n}`;
|
|
224
|
+
}
|
|
225
|
+
function $(t) {
|
|
226
|
+
var e, r;
|
|
227
|
+
if (t.coordinates.length === 0)
|
|
228
|
+
return "MULTIPOLYGON EMPTY";
|
|
229
|
+
const n = `(${t.coordinates.map((o) => `(${o.map((h) => `(${h.map((i) => c(i))})`)})`)})`;
|
|
230
|
+
return `MULTIPOLYGON${a(
|
|
231
|
+
(r = (e = t.coordinates[0]) == null ? void 0 : e[0]) == null ? void 0 : r[0]
|
|
232
|
+
)}${n}`;
|
|
233
|
+
}
|
|
234
|
+
function u(t, n) {
|
|
235
|
+
let e = null;
|
|
236
|
+
const r = t.matchRegex([/^SRID=(\d+);/i]);
|
|
237
|
+
r && (e = parseInt(r[1], 10));
|
|
238
|
+
const o = t.matchType(), h = t.matchDimension(), i = {
|
|
239
|
+
...n,
|
|
240
|
+
srid: e,
|
|
241
|
+
hasZ: h.hasZ,
|
|
242
|
+
hasM: h.hasM
|
|
243
|
+
};
|
|
244
|
+
switch (o) {
|
|
245
|
+
case "Point":
|
|
246
|
+
return g(t, i);
|
|
247
|
+
case "LineString":
|
|
248
|
+
return E(t, i);
|
|
249
|
+
case "Polygon":
|
|
250
|
+
return m(t, i);
|
|
251
|
+
case "MultiPoint":
|
|
252
|
+
return S(t, i);
|
|
253
|
+
case "MultiLineString":
|
|
254
|
+
return y(t, i);
|
|
255
|
+
case "MultiPolygon":
|
|
256
|
+
return x(t, i);
|
|
257
|
+
case "GeometryCollection":
|
|
258
|
+
return P(t, i);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function O(t) {
|
|
262
|
+
switch (t.type) {
|
|
263
|
+
case "Point":
|
|
264
|
+
return T(t);
|
|
265
|
+
case "LineString":
|
|
266
|
+
return N(t);
|
|
267
|
+
case "MultiPoint":
|
|
268
|
+
return L(t);
|
|
269
|
+
case "GeometryCollection":
|
|
270
|
+
return C(t);
|
|
271
|
+
case "Polygon":
|
|
272
|
+
return W(t);
|
|
273
|
+
case "MultiPolygon":
|
|
274
|
+
return $(t);
|
|
275
|
+
case "MultiLineString":
|
|
276
|
+
return I(t);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function Z(t, n = {
|
|
280
|
+
emptyAsNull: !0
|
|
281
|
+
}) {
|
|
282
|
+
return u(new G(t), n);
|
|
283
|
+
}
|
|
284
|
+
export {
|
|
285
|
+
O as geoJSONToWkt,
|
|
286
|
+
Z as wktToGeoJSON
|
|
287
|
+
};
|
umap/storage/fs.py
CHANGED
|
@@ -79,7 +79,7 @@ class FSDataStorage(FileSystemStorage):
|
|
|
79
79
|
"size": self.size(self._base_path(instance) / name),
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
def purge_old_versions(self, instance, keep=None):
|
|
82
|
+
def purge_old_versions(self, instance, keep=None, dry_run=False):
|
|
83
83
|
root = self._base_path(instance)
|
|
84
84
|
versions = self.list_versions(instance)
|
|
85
85
|
if keep is not None:
|
|
@@ -92,7 +92,8 @@ class FSDataStorage(FileSystemStorage):
|
|
|
92
92
|
if keep is not None and instance.geojson.name.endswith(name):
|
|
93
93
|
continue
|
|
94
94
|
try:
|
|
95
|
-
|
|
95
|
+
if not dry_run:
|
|
96
|
+
self.delete(root / name)
|
|
96
97
|
except FileNotFoundError:
|
|
97
98
|
pass
|
|
98
99
|
else:
|
umap/templates/base.html
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{% load umap_tags i18n static %}
|
|
2
2
|
|
|
3
|
+
{% get_current_language as LANGUAGE_CODE %}
|
|
4
|
+
|
|
3
5
|
<!DOCTYPE html>
|
|
4
|
-
<html {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}
|
|
6
|
+
<html {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}
|
|
7
|
+
lang="{{ LANGUAGE_CODE }}">
|
|
5
8
|
<head>
|
|
6
9
|
<title>
|
|
7
10
|
{% block head_title %}
|
umap/tests/base.py
CHANGED
|
@@ -128,7 +128,15 @@ class DataLayerFactory(factory.django.DjangoModelFactory):
|
|
|
128
128
|
def _adjust_kwargs(cls, **kwargs):
|
|
129
129
|
if "data" in kwargs:
|
|
130
130
|
data = copy.deepcopy(kwargs.pop("data"))
|
|
131
|
-
data.setdefault(
|
|
131
|
+
data.setdefault(
|
|
132
|
+
"_umap_options",
|
|
133
|
+
{
|
|
134
|
+
"fields": [
|
|
135
|
+
{"key": "name", "type": "String"},
|
|
136
|
+
{"key": "description", "type": "Text"},
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
)
|
|
132
140
|
if "name" in data["_umap_options"] and kwargs["name"] == cls.name:
|
|
133
141
|
kwargs["name"] = data["_umap_options"]["name"]
|
|
134
142
|
kwargs.setdefault("settings", {})
|
|
@@ -27,6 +27,7 @@ DATALAYER_DATA1 = {
|
|
|
27
27
|
"myboolean": True,
|
|
28
28
|
"mydate": "2024/04/14 12:19:17",
|
|
29
29
|
"maybeempty": "not empty",
|
|
30
|
+
"onlyinone": "blah",
|
|
30
31
|
},
|
|
31
32
|
"geometry": {"type": "Point", "coordinates": [0.065918, 48.385442]},
|
|
32
33
|
},
|
|
@@ -39,6 +40,7 @@ DATALAYER_DATA1 = {
|
|
|
39
40
|
"myboolean": False,
|
|
40
41
|
"mydate": "2024/03/13 12:20:20",
|
|
41
42
|
"maybeempty": "",
|
|
43
|
+
"onlyinone": "ffff",
|
|
42
44
|
},
|
|
43
45
|
"geometry": {"type": "Point", "coordinates": [3.55957, 49.767074]},
|
|
44
46
|
},
|
|
@@ -95,7 +97,7 @@ DATALAYER_DATA2 = {
|
|
|
95
97
|
|
|
96
98
|
def test_simple_equal_rule_at_load(live_server, page, map):
|
|
97
99
|
map.settings["properties"]["rules"] = [
|
|
98
|
-
{"condition": "mytype=odd", "
|
|
100
|
+
{"condition": "mytype=odd", "properties": {"color": "aliceblue"}}
|
|
99
101
|
]
|
|
100
102
|
map.save()
|
|
101
103
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -109,7 +111,7 @@ def test_simple_equal_rule_at_load(live_server, page, map):
|
|
|
109
111
|
|
|
110
112
|
def test_simple_not_equal_rule_at_load(live_server, page, map):
|
|
111
113
|
map.settings["properties"]["rules"] = [
|
|
112
|
-
{"condition": "mytype!=even", "
|
|
114
|
+
{"condition": "mytype!=even", "properties": {"color": "aliceblue"}}
|
|
113
115
|
]
|
|
114
116
|
map.save()
|
|
115
117
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -123,7 +125,7 @@ def test_simple_not_equal_rule_at_load(live_server, page, map):
|
|
|
123
125
|
|
|
124
126
|
def test_gt_rule_with_number_at_load(live_server, page, map):
|
|
125
127
|
map.settings["properties"]["rules"] = [
|
|
126
|
-
{"condition": "mynumber>10", "
|
|
128
|
+
{"condition": "mynumber>10", "properties": {"color": "aliceblue"}}
|
|
127
129
|
]
|
|
128
130
|
map.save()
|
|
129
131
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -137,7 +139,7 @@ def test_gt_rule_with_number_at_load(live_server, page, map):
|
|
|
137
139
|
|
|
138
140
|
def test_lt_rule_with_number_at_load(live_server, page, map):
|
|
139
141
|
map.settings["properties"]["rules"] = [
|
|
140
|
-
{"condition": "mynumber<14", "
|
|
142
|
+
{"condition": "mynumber<14", "properties": {"color": "aliceblue"}}
|
|
141
143
|
]
|
|
142
144
|
map.save()
|
|
143
145
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -151,7 +153,7 @@ def test_lt_rule_with_number_at_load(live_server, page, map):
|
|
|
151
153
|
|
|
152
154
|
def test_lt_rule_with_float_at_load(live_server, page, map):
|
|
153
155
|
map.settings["properties"]["rules"] = [
|
|
154
|
-
{"condition": "mynumber<12.3", "
|
|
156
|
+
{"condition": "mynumber<12.3", "properties": {"color": "aliceblue"}}
|
|
155
157
|
]
|
|
156
158
|
map.save()
|
|
157
159
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -165,7 +167,7 @@ def test_lt_rule_with_float_at_load(live_server, page, map):
|
|
|
165
167
|
|
|
166
168
|
def test_equal_rule_with_boolean_at_load(live_server, page, map):
|
|
167
169
|
map.settings["properties"]["rules"] = [
|
|
168
|
-
{"condition": "myboolean=true", "
|
|
170
|
+
{"condition": "myboolean=true", "properties": {"color": "aliceblue"}}
|
|
169
171
|
]
|
|
170
172
|
map.save()
|
|
171
173
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -179,7 +181,7 @@ def test_equal_rule_with_boolean_at_load(live_server, page, map):
|
|
|
179
181
|
|
|
180
182
|
def test_equal_rule_with_boolean_not_true_at_load(live_server, page, map):
|
|
181
183
|
map.settings["properties"]["rules"] = [
|
|
182
|
-
{"condition": "myboolean!=true", "
|
|
184
|
+
{"condition": "myboolean!=true", "properties": {"color": "aliceblue"}}
|
|
183
185
|
]
|
|
184
186
|
map.save()
|
|
185
187
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -193,7 +195,7 @@ def test_equal_rule_with_boolean_not_true_at_load(live_server, page, map):
|
|
|
193
195
|
|
|
194
196
|
def test_equal_rule_with_boolean_false_at_load(live_server, page, map):
|
|
195
197
|
map.settings["properties"]["rules"] = [
|
|
196
|
-
{"condition": "myboolean=false", "
|
|
198
|
+
{"condition": "myboolean=false", "properties": {"color": "aliceblue"}}
|
|
197
199
|
]
|
|
198
200
|
map.save()
|
|
199
201
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -207,7 +209,7 @@ def test_equal_rule_with_boolean_false_at_load(live_server, page, map):
|
|
|
207
209
|
|
|
208
210
|
def test_equal_rule_with_boolean_not_false_at_load(live_server, page, map):
|
|
209
211
|
map.settings["properties"]["rules"] = [
|
|
210
|
-
{"condition": "myboolean!=false", "
|
|
212
|
+
{"condition": "myboolean!=false", "properties": {"color": "aliceblue"}}
|
|
211
213
|
]
|
|
212
214
|
map.save()
|
|
213
215
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -221,7 +223,7 @@ def test_equal_rule_with_boolean_not_false_at_load(live_server, page, map):
|
|
|
221
223
|
|
|
222
224
|
def test_empty_rule_at_load(live_server, page, map):
|
|
223
225
|
map.settings["properties"]["rules"] = [
|
|
224
|
-
{"condition": "maybeempty=", "
|
|
226
|
+
{"condition": "maybeempty=", "properties": {"color": "aliceblue"}}
|
|
225
227
|
]
|
|
226
228
|
map.save()
|
|
227
229
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -235,7 +237,7 @@ def test_empty_rule_at_load(live_server, page, map):
|
|
|
235
237
|
|
|
236
238
|
def test_not_empty_rule_at_load(live_server, page, map):
|
|
237
239
|
map.settings["properties"]["rules"] = [
|
|
238
|
-
{"condition": "maybeempty!=", "
|
|
240
|
+
{"condition": "maybeempty!=", "properties": {"color": "aliceblue"}}
|
|
239
241
|
]
|
|
240
242
|
map.save()
|
|
241
243
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -270,7 +272,7 @@ def test_can_create_new_rule(live_server, page, openmap):
|
|
|
270
272
|
|
|
271
273
|
def test_can_deactive_rule_from_list(live_server, page, openmap):
|
|
272
274
|
openmap.settings["properties"]["rules"] = [
|
|
273
|
-
{"condition": "mytype=odd", "
|
|
275
|
+
{"condition": "mytype=odd", "properties": {"color": "aliceblue"}}
|
|
274
276
|
]
|
|
275
277
|
openmap.save()
|
|
276
278
|
DataLayerFactory(map=openmap, data=DATALAYER_DATA1)
|
|
@@ -299,9 +301,17 @@ def test_autocomplete_datalist(live_server, page, openmap):
|
|
|
299
301
|
page.get_by_role("button", name="Add rule").click()
|
|
300
302
|
panel = page.locator(".panel.right.on")
|
|
301
303
|
datalist = panel.locator(".umap-field-condition datalist option")
|
|
302
|
-
expect(datalist).to_have_count(
|
|
304
|
+
expect(datalist).to_have_count(7)
|
|
303
305
|
values = {option.inner_text() for option in datalist.all()}
|
|
304
|
-
assert values == {
|
|
306
|
+
assert values == {
|
|
307
|
+
"myboolean",
|
|
308
|
+
"mytype",
|
|
309
|
+
"mynumber",
|
|
310
|
+
"mydate",
|
|
311
|
+
"name",
|
|
312
|
+
"maybeempty",
|
|
313
|
+
"onlyinone",
|
|
314
|
+
}
|
|
305
315
|
page.get_by_placeholder("key=value or key!=value").fill("mytype")
|
|
306
316
|
expect(datalist).to_have_count(4)
|
|
307
317
|
values = {option.inner_text() for option in datalist.all()}
|
|
@@ -314,8 +324,8 @@ def test_autocomplete_datalist(live_server, page, openmap):
|
|
|
314
324
|
|
|
315
325
|
def test_can_combine_rules(live_server, page, map):
|
|
316
326
|
map.settings["properties"]["rules"] = [
|
|
317
|
-
{"condition": "mytype=odd", "
|
|
318
|
-
{"condition": "mynumber>10", "
|
|
327
|
+
{"condition": "mytype=odd", "properties": {"color": "aliceblue"}},
|
|
328
|
+
{"condition": "mynumber>10", "properties": {"iconClass": "Drop"}},
|
|
319
329
|
]
|
|
320
330
|
map.save()
|
|
321
331
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -333,8 +343,8 @@ def test_can_combine_rules(live_server, page, map):
|
|
|
333
343
|
|
|
334
344
|
def test_first_matching_rule_wins_on_given_property(live_server, page, map):
|
|
335
345
|
map.settings["properties"]["rules"] = [
|
|
336
|
-
{"condition": "mytype=odd", "
|
|
337
|
-
{"condition": "mytype!=even", "
|
|
346
|
+
{"condition": "mytype=odd", "properties": {"color": "aliceblue"}},
|
|
347
|
+
{"condition": "mytype!=even", "properties": {"color": "darkred"}},
|
|
338
348
|
]
|
|
339
349
|
map.save()
|
|
340
350
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
|
@@ -348,12 +358,12 @@ def test_first_matching_rule_wins_on_given_property(live_server, page, map):
|
|
|
348
358
|
|
|
349
359
|
def test_rules_from_datalayer(live_server, page, map):
|
|
350
360
|
map.settings["properties"]["rules"] = [
|
|
351
|
-
{"condition": "mytype=odd", "
|
|
361
|
+
{"condition": "mytype=odd", "properties": {"color": "darkred"}}
|
|
352
362
|
]
|
|
353
363
|
map.save()
|
|
354
364
|
data = deepcopy(DATALAYER_DATA1)
|
|
355
365
|
data["_umap_options"]["rules"] = [
|
|
356
|
-
{"condition": "mytype=odd", "
|
|
366
|
+
{"condition": "mytype=odd", "properties": {"color": "aliceblue"}}
|
|
357
367
|
]
|
|
358
368
|
DataLayerFactory(map=map, data=data)
|
|
359
369
|
DataLayerFactory(map=map, data=DATALAYER_DATA2)
|
|
@@ -365,3 +375,35 @@ def test_rules_from_datalayer(live_server, page, map):
|
|
|
365
375
|
assert colors.count("rgb(240, 248, 255)") == 1
|
|
366
376
|
# Dark Red as for map global rules
|
|
367
377
|
assert colors.count("rgb(139, 0, 0)") == 2
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def test_rules_in_caption(live_server, page, map):
|
|
381
|
+
map.settings["properties"]["rules"] = [
|
|
382
|
+
{
|
|
383
|
+
"condition": "mytype=odd",
|
|
384
|
+
"name": "Rule shown twice",
|
|
385
|
+
"properties": {"color": "darkred"},
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"condition": "onlyinone=fff",
|
|
389
|
+
"name": "Rule shown once",
|
|
390
|
+
"properties": {"color": "darkred"},
|
|
391
|
+
},
|
|
392
|
+
]
|
|
393
|
+
map.settings["properties"]["onLoadPanel"] = "caption"
|
|
394
|
+
map.save()
|
|
395
|
+
data = deepcopy(DATALAYER_DATA1)
|
|
396
|
+
data["_umap_options"]["rules"] = [
|
|
397
|
+
{
|
|
398
|
+
"condition": "myboolean=true",
|
|
399
|
+
"name": "Rule shown also once",
|
|
400
|
+
"properties": {"color": "aliceblue"},
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
DataLayerFactory(map=map, data=data)
|
|
404
|
+
DataLayerFactory(map=map, data=DATALAYER_DATA2)
|
|
405
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
|
|
406
|
+
panel = page.locator(".panel.left.on")
|
|
407
|
+
expect(panel.get_by_text("Rule shown twice")).to_have_count(2)
|
|
408
|
+
expect(panel.get_by_text("Rule shown once")).to_have_count(1)
|
|
409
|
+
expect(panel.get_by_text("Rule shown also once")).to_have_count(1)
|
|
@@ -221,7 +221,7 @@ def test_deleting_datalayer_should_remove_from_caption(
|
|
|
221
221
|
def test_can_edit_datalayer_name_in_list(live_server, openmap, datalayer, page):
|
|
222
222
|
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
|
223
223
|
page.get_by_role("button", name="Manage layers").click()
|
|
224
|
-
page.get_by_text("test datalayer").
|
|
224
|
+
page.get_by_text("test datalayer").dblclick()
|
|
225
225
|
page.get_by_text("test datalayer").fill("test datalayer foobar")
|
|
226
226
|
page.get_by_role("button", name="Open browser").click()
|
|
227
227
|
expect(
|
|
@@ -125,7 +125,7 @@ def test_add_property_from_feature_properties_panel(
|
|
|
125
125
|
):
|
|
126
126
|
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
|
127
127
|
page.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
|
|
128
|
-
page.get_by_role("button", name="Add a new
|
|
128
|
+
page.get_by_role("button", name="Add a new field").click()
|
|
129
129
|
page.locator('input[name="prompt"]').fill("newprop")
|
|
130
130
|
page.get_by_role("button", name="OK").click()
|
|
131
131
|
expect(page.locator(".panel.right").get_by_text("newprop")).to_be_visible()
|
|
@@ -104,6 +104,16 @@ def test_umap_export(map, live_server, bootstrap, page):
|
|
|
104
104
|
"browsable": True,
|
|
105
105
|
"displayOnLoad": True,
|
|
106
106
|
"name": "test datalayer",
|
|
107
|
+
"fields": [
|
|
108
|
+
{
|
|
109
|
+
"key": "name",
|
|
110
|
+
"type": "String",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"key": "description",
|
|
114
|
+
"type": "Text",
|
|
115
|
+
},
|
|
116
|
+
],
|
|
107
117
|
},
|
|
108
118
|
"features": [
|
|
109
119
|
{
|