Skip to content

Commit 565498c

Browse files
committed
wip: allow to change target of new filter
1 parent 66e9fe2 commit 565498c

File tree

4 files changed

+154
-7
lines changed

4 files changed

+154
-7
lines changed

umap/static/umap/css/form.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ select {
9494
border-width: 1px;
9595
}
9696

97+
.dark select[disabled],
98+
select[disabled] {
99+
background-color: var(--color-mediumGray);
100+
color: var(--color-lightGray);
101+
cursor: not-allowed;
102+
}
103+
97104
select[multiple="multiple"] {
98105
height: auto;
99106
}

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

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,17 +283,30 @@ export default class Filters {
283283
if (['Number', 'Date', 'Datetime'].includes(field?.type)) {
284284
widget = 'minmax'
285285
}
286-
const properties = { name, widget, ...(this.defined.get(name) || {}) }
286+
const properties = {
287+
target: this._parent,
288+
name,
289+
widget,
290+
...(this.defined.get(name) || {}),
291+
}
287292
const fieldKeys = name
288293
? [name]
289294
: ['', ...this._parent.fieldKeys.filter((key) => !this.defined.has(key))]
290295
const metadata = [
296+
[
297+
'target',
298+
{
299+
handler: 'FilterTargetSelect',
300+
label: translate('Apply filter to'),
301+
disabled: Boolean(name),
302+
},
303+
],
291304
[
292305
'name',
293306
{
294307
handler: 'Select',
295308
selectOptions: fieldKeys,
296-
label: translate('Field to filter on'),
309+
label: translate('Filter on'),
297310
},
298311
],
299312
[
@@ -309,7 +322,7 @@ export default class Filters {
309322
},
310323
],
311324
]
312-
const form = new Form(properties, metadata)
325+
const form = new Form(properties, metadata, { umap: this._umap })
313326
let label
314327
if (name) {
315328
label = translate('Edit filter')
@@ -331,13 +344,16 @@ export default class Filters {
331344
})
332345

333346
return this._umap.dialog.open({ template: container }).then(() => {
347+
const target = properties.target
334348
if (!properties.name) return
335349
if (name) {
336-
this.update({ ...properties })
350+
target.filters.update({ ...properties })
337351
} else {
338-
this.add({ ...properties })
352+
target.filters.add({ ...properties })
339353
}
340-
this._parent.edit().then((panel) => panel.scrollTo('details#fields-management'))
354+
target.filters._parent
355+
.edit()
356+
.then((panel) => panel.scrollTo('details#fields-management'))
341357
})
342358
}
343359

@@ -408,7 +424,7 @@ Fields.MinMaxBase = class extends Fields.FilterBase {
408424
}
409425

410426
prepareForHTML(value) {
411-
return value.valueOf()
427+
return value?.valueOf() || null
412428
}
413429

414430
getTemplate() {
@@ -539,3 +555,42 @@ Fields.FilterByDateTime = class extends Fields.FilterByDate {
539555
return this.toLocaleDateTime(value).toISOString().slice(0, -1)
540556
}
541557
}
558+
559+
Fields.FilterTargetSelect = class extends Fields.Select {
560+
getOptions() {
561+
const options = []
562+
if (this.builder.properties.umap.fields.size) {
563+
options.push([
564+
`map:${this.builder.properties.umap.id}`,
565+
`${this.builder.properties.umap.properties.name} (${translate('all layers')})`,
566+
])
567+
}
568+
this.builder.properties.umap.datalayers.reverse().map((datalayer) => {
569+
if (datalayer.isBrowsable() && datalayer.fields.size) {
570+
options.push([
571+
`layer:${datalayer.id}`,
572+
`${datalayer.getName()} (${translate('single layer')})`,
573+
])
574+
}
575+
})
576+
return options
577+
}
578+
579+
toHTML() {
580+
if (!this.obj.target) return null
581+
// TODO: better way to check for class
582+
// Importing DataLayer will end in circular import
583+
const type = this.obj.target._umap ? 'layer' : 'map'
584+
return `${type}:${this.obj.target?.id}`
585+
}
586+
587+
toJS() {
588+
const value = this.value()
589+
if (!value) return null
590+
const [type, id] = value.split(':')
591+
if (type === 'map') {
592+
return this.builder.properties.umap
593+
}
594+
return this.builder.properties.umap.datalayers[id]
595+
}
596+
}

umap/static/umap/js/modules/form/fields.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ Fields.Select = class extends Fields.Base {
390390

391391
build() {
392392
this.select = this.elements.select
393+
if (this.properties.disabled) {
394+
this.select.disabled = true
395+
}
393396
this.validValues = []
394397
this.buildOptions()
395398
this.select.addEventListener('change', () => this.sync())

umap/tests/integration/test_filters.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,85 @@ def test_can_create_filter_from_new_field(live_server, page, openmap):
468468
"widget": "checkbox",
469469
},
470470
}
471+
472+
473+
def test_can_create_new_filter_on_map_from_panel(live_server, page, openmap):
474+
openmap.settings["properties"]["onLoadPanel"] = "datafilters"
475+
openmap.settings["properties"]["fields"] = [
476+
{"key": "name", "type": "String"},
477+
{"key": "foobar", "type": "Number"},
478+
{"key": "description", "type": "Text"},
479+
]
480+
openmap.save()
481+
DataLayerFactory(map=openmap, data=DATALAYER_DATA1)
482+
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
483+
page.get_by_role("button", name="Add filter").click()
484+
page.get_by_label("Filter on").select_option("foobar")
485+
page.get_by_role("textbox", name="Human readable name of the").fill("Foo Bar")
486+
page.wait_for_timeout(300)
487+
page.get_by_text("radio").click()
488+
page.get_by_role("button", name="OK").click()
489+
expect(
490+
page.locator(".panel.left").get_by_role("group", name="Foo Bar")
491+
).to_be_visible()
492+
with page.expect_response(re.compile("./update/settings/.*")):
493+
page.get_by_role("button", name="Save", exact=True).click()
494+
saved = Map.objects.first()
495+
assert saved.settings["properties"]["filters"] == {
496+
"foobar": {"label": "Foo Bar", "widget": "radio"}
497+
}
498+
499+
500+
def test_can_create_new_filter_on_datalayer_from_panel(live_server, page, openmap):
501+
openmap.settings["properties"]["fields"] = [
502+
{"key": "name", "type": "String"},
503+
{"key": "foobar", "type": "Number"},
504+
{"key": "description", "type": "Text"},
505+
]
506+
openmap.save()
507+
datalayer = DataLayerFactory(map=openmap, data=DATALAYER_DATA1)
508+
page.goto(
509+
f"{live_server.url}{openmap.get_absolute_url()}?edit&onLoadPanel=datafilters"
510+
)
511+
page.get_by_role("button", name="Add filter").click()
512+
expect(page.get_by_label("Apply filter to")).to_have_value(f"map:{openmap.pk}")
513+
page.get_by_label("Apply filter to").select_option(f"layer:{datalayer.pk}")
514+
page.get_by_label("Filter on").select_option("mynumber")
515+
page.get_by_role("textbox", name="Human readable name of the").fill("Foo Bar")
516+
page.wait_for_timeout(300)
517+
page.get_by_text("radio").click()
518+
page.get_by_role("button", name="OK").click()
519+
expect(
520+
page.locator(".panel.left").get_by_role("group", name="Foo Bar")
521+
).to_be_visible()
522+
with page.expect_response(re.compile("./datalayer/update/.*")):
523+
page.get_by_role("button", name="Save", exact=True).click()
524+
saved = DataLayer.objects.first()
525+
assert saved.settings["filters"] == {
526+
"mynumber": {"label": "Foo Bar", "widget": "radio"}
527+
}
528+
529+
530+
def test_can_edit_filter_from_panel(live_server, page, openmap):
531+
openmap.settings["properties"]["fields"] = [
532+
{"key": "name", "type": "String"},
533+
{"key": "foobar", "type": "Number"},
534+
{"key": "description", "type": "Text"},
535+
]
536+
openmap.settings["properties"]["filters"] = {
537+
"foobar": {"widget": "minmax", "label": "Foo Bar"},
538+
"name": {"widget": "checkbox", "label": "Bar Foo"},
539+
}
540+
openmap.save()
541+
page.goto(
542+
f"{live_server.url}{openmap.get_absolute_url()}?edit&onLoadPanel=datafilters"
543+
)
544+
page.get_by_role("group", name="Foo Bar").get_by_role("button").click()
545+
expect(page.get_by_label("Apply filter to")).to_have_value("map:1")
546+
expect(page.get_by_label("Apply filter to")).to_be_disabled()
547+
page.get_by_role("textbox", name="Human readable name of the").fill("Foo Bar Baz")
548+
page.wait_for_timeout(300) # Input throttling.
549+
page.get_by_role("button", name="OK").click()
550+
expect(
551+
page.get_by_role("group", name="Foo Bar Baz").locator("legend")
552+
).to_be_visible()

0 commit comments

Comments
 (0)