Skip to content

Commit aa84d99

Browse files
wip: edit field and filter on the right parent from tableeditor
Co-authored-by: David Larlet <[email protected]>
1 parent fd1e16d commit aa84d99

File tree

3 files changed

+80
-42
lines changed

3 files changed

+80
-42
lines changed

umap/static/umap/js/modules/filters.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,12 @@ export default class Filters {
291291
}
292292

293293
filterForm(name) {
294-
const properties = { name, ...(this.defined.get(name) || {}) }
294+
let widget = WIDGETS[0]
295+
const field = this.#parent.fields.get(name)
296+
if (['Number', 'Date', 'Datetime'].includes(field?.type)) {
297+
widget = 'minmax'
298+
}
299+
const properties = { name, widget, ...(this.defined.get(name) || {}) }
295300
const fieldKeys = name
296301
? [name]
297302
: ['', ...this.#parent.fieldKeys.filter((key) => !this.defined.has(key))]

umap/static/umap/js/modules/tableeditor.js

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,53 +31,72 @@ export default class TableEditor extends WithTemplate {
3131
this.elements.body.addEventListener('keydown', (event) => this.onKeyDown(event))
3232
this.elements.header.addEventListener('click', (event) => {
3333
const property = event.target.dataset.property
34-
if (property) this.openHeaderMenu(property)
34+
const parentType = event.target.dataset.fieldParent
35+
if (property)
36+
this.openHeaderMenu(
37+
property,
38+
parentType === 'map' ? this._umap : this.datalayer
39+
)
3540
})
3641
}
3742

38-
openHeaderMenu(property) {
43+
openHeaderMenu(name, parent) {
3944
const actions = []
40-
let filterItem
41-
if (this.datalayer.filters.has(property)) {
42-
filterItem = {
43-
label: translate('Remove filter for this field'),
44-
action: () => {
45-
this.datalayer.filters.remove(property)
46-
this._umap.browser.open('filters')
47-
},
48-
}
45+
let actionLabel
46+
if (parent.filters.has(name)) {
47+
actionLabel = translate('Edit filter for this field')
4948
} else {
50-
filterItem = {
51-
label: translate('Add filter for this field'),
52-
action: () => {
53-
this.datalayer.filters.add({ name: property })
54-
this._umap.browser.open('filters')
55-
},
56-
}
49+
actionLabel = translate('Add filter for this field')
5750
}
58-
actions.push(filterItem)
59-
if (!this.datalayer.isRemoteLayer()) {
51+
actions.push({
52+
label: actionLabel,
53+
action: () => {
54+
parent.filters.filterForm(name)
55+
this._umap.browser.open('filters')
56+
},
57+
})
58+
// Only allow editing fields for map and local datalayer.
59+
if (!parent.isRemoteLayer?.()) {
6060
actions.push({
6161
label: translate('Edit this field'),
62-
action: () => this.editField(property),
62+
action: () => {
63+
parent.fields.editField(name).then(() => this.open())
64+
},
6365
})
6466
actions.push({
6567
label: translate('Delete this field'),
66-
action: () => this.deleteField(property),
68+
action: () => {
69+
parent.fields.confirmDelete(name).then(() => this.open())
70+
},
6771
})
6872
}
6973
this.contextmenu.open(event, actions)
7074
}
7175

76+
get fields() {
77+
return [
78+
...this.datalayer.fields.all().map((field) => {
79+
const copy = { ...field }
80+
copy.parent = 'datalayer'
81+
return copy
82+
}),
83+
...this._umap.fields.all().map((field) => {
84+
const copy = { ...field }
85+
copy.parent = 'map'
86+
return copy
87+
}),
88+
]
89+
}
90+
7291
renderHeaders() {
7392
this.elements.header.innerHTML = ''
7493
const th = loadTemplate('<th><input type="checkbox" /></th>')
7594
const checkbox = th.firstChild
7695
this.elements.header.appendChild(th)
77-
for (const field of this.datalayer.fields.all()) {
96+
for (const field of this.fields) {
7897
this.elements.header.appendChild(
7998
loadTemplate(
80-
`<th>${field.key}<button data-property="${field.key}" class="flat" aria-label="${translate('Advanced actions')}">…</button></th>`
99+
`<th>${field.key}<button data-property="${field.key}" data-field-parent="${field.parent}" class="flat" aria-label="${translate('Advanced actions')}">…</button></th>`
81100
)
82101
)
83102
}
@@ -94,25 +113,15 @@ export default class TableEditor extends WithTemplate {
94113
this.datalayer.features.forEach((feature) => {
95114
if (feature.isFiltered()) return
96115
if (inBbox && !feature.isOnScreen(bounds)) return
97-
const tds = this.datalayer.fields
98-
.all()
99-
.map(
100-
(field) =>
101-
`<td tabindex="0" data-property="${field.key}">${feature.properties[field.key] ?? ''}</td>`
102-
)
116+
const tds = this.fields.map(
117+
(field) =>
118+
`<td tabindex="0" data-property="${field.key}">${feature.properties[field.key] ?? ''}</td>`
119+
)
103120
html += `<tr data-feature="${feature.id}"><th><input type="checkbox" /></th>${tds.join('')}</tr>`
104121
})
105122
this.elements.body.innerHTML = html
106123
}
107124

108-
editField(name) {
109-
this.datalayer.fields.editField(name).then(() => this.open())
110-
}
111-
112-
deleteField(name) {
113-
this.datalayer.fields.confirmDelete(name).then(() => this.open())
114-
}
115-
116125
addField() {
117126
this.datalayer.fields.editField().then(() => this.open())
118127
}

umap/tests/integration/test_tableeditor.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from playwright.sync_api import expect
66

7-
from umap.models import DataLayer
7+
from umap.models import DataLayer, Map
88

99
from ..base import DataLayerFactory
1010

@@ -116,7 +116,7 @@ def test_cannot_add_property_with_a_dot(live_server, openmap, datalayer, page):
116116
expect(page.locator("table th button[data-property=name]")).to_have_count(1)
117117

118118

119-
def test_rename_property(live_server, openmap, page):
119+
def test_rename_field(live_server, openmap, page):
120120
DataLayerFactory(map=openmap, data=DATALAYER_DATA)
121121
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit#6/48.093/1.890")
122122
page.get_by_role("button", name="Manage layers").click()
@@ -142,7 +142,7 @@ def test_rename_property(live_server, openmap, page):
142142
expect(page.locator(".panel.right .umap-field-mytype")).to_be_visible()
143143

144144

145-
def test_delete_property(live_server, openmap, page):
145+
def test_delete_field(live_server, openmap, page):
146146
DataLayerFactory(map=openmap, data=DATALAYER_DATA)
147147
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit#6/48.093/1.890")
148148
page.get_by_role("button", name="Manage layers").click()
@@ -203,6 +203,7 @@ def test_filter_and_delete_rows(live_server, openmap, page):
203203
expect(page.locator(".leaflet-marker-icon")).to_have_count(4)
204204
table.locator("thead button[data-property=mytype]").click()
205205
page.get_by_role("button", name="Add filter for this field").click()
206+
page.get_by_role("button", name="OK").click()
206207
expect(panel).to_be_visible()
207208
panel.get_by_label("even").check()
208209
table.locator("thead").get_by_role("checkbox").check()
@@ -214,3 +215,26 @@ def test_filter_and_delete_rows(live_server, openmap, page):
214215
expect(table.get_by_text("Point 3")).to_be_visible()
215216
expect(table.get_by_text("Point 2")).to_be_hidden()
216217
expect(table.get_by_text("Point 4")).to_be_hidden()
218+
219+
220+
def test_add_filter_on_map_field(live_server, openmap, page):
221+
openmap.settings["properties"]["fields"] = [{"key": "mynumber", "type": "Number"}]
222+
openmap.save()
223+
table = page.locator(".panel.full table")
224+
DataLayerFactory(map=openmap, data=DATALAYER_DATA)
225+
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit#6/48.093/1.890")
226+
page.get_by_role("button", name="Manage layers").click()
227+
page.locator(".panel").get_by_title("Edit properties in a table").click()
228+
table.locator("thead button[data-property=mynumber]").click()
229+
page.get_by_role("button", name="Add filter for this field").click()
230+
expect(page.locator("dialog").get_by_label("minmax", exact=True)).to_be_checked()
231+
page.locator("dialog").get_by_label("human readable name").fill("My Fun Filter")
232+
page.wait_for_timeout(300) # Throttling…
233+
page.get_by_role("button", name="OK").click()
234+
expect(page.locator(".panel.left.on").get_by_text("My Fun Filter")).to_be_visible()
235+
with page.expect_response(re.compile("./update/settings/.*")):
236+
page.get_by_role("button", name="Save").click()
237+
saved = Map.objects.first()
238+
assert saved.settings["properties"]["filters"] == {
239+
"mynumber": {"widget": "minmax", "label": "My Fun Filter"}
240+
}

0 commit comments

Comments
 (0)