mirror of
https://github.com/umap-project/umap.git
synced 2025-04-28 19:42:36 +02:00
feat: allow to configure the default label keys per instance (#2291)
fix #2289 Let's add "nom" in OSM France and ANCT instances, then, to make users experience smoother (a lot of imported data contains a "nom" column, and no "name" nor "title").
This commit is contained in:
commit
2c601e483d
11 changed files with 72 additions and 27 deletions
|
@ -175,11 +175,6 @@ UMAP_EXTRA_URLS = {
|
|||
}
|
||||
```
|
||||
|
||||
#### UMAP_KEEP_VERSIONS
|
||||
|
||||
How many datalayer versions to keep. 10 by default.
|
||||
|
||||
|
||||
#### UMAP_DEFAULT_EDIT_STATUS
|
||||
|
||||
Define the map default edit status.
|
||||
|
@ -270,6 +265,16 @@ Available importers:
|
|||
- `communesfr`: download French communes boundaries, from https://geo.api.gouv.fr/
|
||||
- `datasets`: define URLs you want to promote to users, with a `name` and a `format`
|
||||
|
||||
#### UMAP_KEEP_VERSIONS
|
||||
|
||||
How many datalayer versions to keep. 10 by default.
|
||||
|
||||
#### UMAP_LABEL_KEYS
|
||||
|
||||
List of properties to consider as "Feature label" (to show in popup or in browser).
|
||||
|
||||
UMAP_LABEL_KEYS = ["name", "title"]
|
||||
|
||||
#### UMAP_MAPS_PER_PAGE
|
||||
|
||||
How many maps to show in maps list, like search or home page.
|
||||
|
|
|
@ -273,6 +273,7 @@ UMAP_HOME_FEED = "latest"
|
|||
UMAP_IMPORTERS = {}
|
||||
UMAP_HOST_INFOS = {}
|
||||
UMAP_PURGATORY_ROOT = "/tmp/umappurgatory"
|
||||
UMAP_LABEL_KEYS = ["name", "title"]
|
||||
|
||||
UMAP_READONLY = env("UMAP_READONLY", default=False)
|
||||
UMAP_GZIP = True
|
||||
|
|
|
@ -165,7 +165,9 @@ class Feature {
|
|||
}
|
||||
|
||||
getSlug() {
|
||||
return this.properties[this._umap.getProperty('slugKey') || 'name'] || ''
|
||||
return (
|
||||
this.properties[this._umap.getProperty('slugKey') || U.DEFAULT_LABEL_KEY] || ''
|
||||
)
|
||||
}
|
||||
|
||||
getPermalink() {
|
||||
|
@ -234,15 +236,23 @@ class Feature {
|
|||
container.appendChild(builder.build())
|
||||
|
||||
const properties = []
|
||||
let labelKeyFound = undefined
|
||||
for (const property of this.datalayer._propertiesIndex) {
|
||||
if (['name', 'description'].includes(property)) {
|
||||
if (!labelKeyFound && U.LABEL_KEYS.includes(property)) {
|
||||
labelKeyFound = property
|
||||
continue
|
||||
}
|
||||
if (property === 'description') {
|
||||
continue
|
||||
}
|
||||
properties.push([`properties.${property}`, { label: property }])
|
||||
}
|
||||
// We always want name and description for now (properties management to come)
|
||||
properties.unshift('properties.description')
|
||||
properties.unshift('properties.name')
|
||||
if (!labelKeyFound) {
|
||||
labelKeyFound = U.DEFAULT_LABEL_KEY
|
||||
}
|
||||
properties.unshift([`properties.${labelKeyFound}`, { label: labelKeyFound }])
|
||||
builder = new U.FormBuilder(this, properties, {
|
||||
id: 'umap-feature-properties',
|
||||
})
|
||||
|
@ -255,7 +265,7 @@ class Feature {
|
|||
this.getAdvancedEditActions(advancedActions)
|
||||
const onLoad = this._umap.editPanel.open({ content: container })
|
||||
onLoad.then(() => {
|
||||
builder.helpers['properties.name'].input.focus()
|
||||
builder.helpers[`properties.${labelKeyFound}`].input.focus()
|
||||
})
|
||||
this._umap.editedFeature = this
|
||||
if (!this.ui.isOnScreen(this._umap._leafletMap.getBounds())) this.zoomTo(event)
|
||||
|
@ -316,19 +326,21 @@ class Feature {
|
|||
|
||||
endEdit() {}
|
||||
|
||||
getDisplayName(fallback) {
|
||||
const key = this.getOption('labelKey') || 'name'
|
||||
getDisplayName() {
|
||||
const keys = U.LABEL_KEYS.slice() // Copy.
|
||||
const labelKey = this.getOption('labelKey')
|
||||
// Variables mode.
|
||||
if (Utils.hasVar(key)) {
|
||||
return Utils.greedyTemplate(key, this.extendedProperties())
|
||||
if (labelKey) {
|
||||
if (Utils.hasVar(labelKey)) {
|
||||
return Utils.greedyTemplate(labelKey, this.extendedProperties())
|
||||
}
|
||||
// Simple mode.
|
||||
return (
|
||||
this.properties[key] ||
|
||||
this.properties.title ||
|
||||
fallback ||
|
||||
this.datalayer.getName()
|
||||
)
|
||||
keys.unshift(labelKey)
|
||||
}
|
||||
for (const key of keys) {
|
||||
const value = this.properties[key]
|
||||
if (value) return value
|
||||
}
|
||||
return this.datalayer.getName()
|
||||
}
|
||||
|
||||
hasPopupFooter() {
|
||||
|
|
|
@ -289,7 +289,7 @@ export class DataLayer extends ServerStored {
|
|||
|
||||
reindex() {
|
||||
const features = Object.values(this._features)
|
||||
Utils.sortFeatures(features, this._umap.getProperty('sortKey'), U.lang)
|
||||
this.sortFeatures(features)
|
||||
this._index = features.map((feature) => stamp(feature))
|
||||
}
|
||||
|
||||
|
@ -450,6 +450,11 @@ export class DataLayer extends ServerStored {
|
|||
}
|
||||
}
|
||||
|
||||
sortFeatures(collection) {
|
||||
const sortKeys = this._umap.getProperty('sortKey') || U.DEFAULT_LABEL_KEY
|
||||
return Utils.sortFeatures(collection, sortKeys, U.lang)
|
||||
}
|
||||
|
||||
makeFeatures(geojson = {}, sync = true) {
|
||||
if (geojson.type === 'Feature' || geojson.coordinates) {
|
||||
geojson = [geojson]
|
||||
|
@ -458,7 +463,7 @@ export class DataLayer extends ServerStored {
|
|||
? geojson
|
||||
: geojson.features || geojson.geometries
|
||||
if (!collection) return
|
||||
Utils.sortFeatures(collection, this._umap.getProperty('sortKey'), U.lang)
|
||||
this.sortFeatures(collection)
|
||||
for (const feature of collection) {
|
||||
this.makeFeature(feature, sync)
|
||||
}
|
||||
|
|
|
@ -115,7 +115,9 @@ class Table extends TitleMixin(PopupTemplate) {
|
|||
const table = document.createElement('table')
|
||||
|
||||
for (const key in feature.properties) {
|
||||
if (typeof feature.properties[key] === 'object' || key === 'name') continue
|
||||
if (typeof feature.properties[key] === 'object' || U.LABEL_KEYS.includes(key)) {
|
||||
continue
|
||||
}
|
||||
table.appendChild(this.makeRow(feature, key))
|
||||
}
|
||||
return table
|
||||
|
|
|
@ -75,7 +75,7 @@ const FeatureMixin = {
|
|||
|
||||
resetTooltip: function () {
|
||||
if (!this.feature.hasGeom()) return
|
||||
const displayName = this.feature.getDisplayName(null)
|
||||
const displayName = this.feature.getDisplayName()
|
||||
let showLabel = this.feature.getOption('showLabel')
|
||||
const oldLabelHover = this.feature.getOption('labelHover')
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ export default class TableEditor extends WithTemplate {
|
|||
resetProperties() {
|
||||
this.properties = this.datalayer._propertiesIndex
|
||||
if (this.properties.length === 0) {
|
||||
this.properties = ['name', 'description']
|
||||
this.properties = [U.DEFAULT_LABEL_KEY, 'description']
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@ export default class Umap extends ServerStored {
|
|||
// To be used in javascript APIs
|
||||
if (geojson.properties.lang) U.lang = geojson.properties.lang
|
||||
|
||||
// Make it available to utils, without needing a reference to `Umap`.
|
||||
U.LABEL_KEYS = geojson.properties.defaultLabelKeys || []
|
||||
U.DEFAULT_LABEL_KEY = U.LABEL_KEYS[0] || 'name'
|
||||
|
||||
this.setPropertiesFromQueryString()
|
||||
|
||||
// Needed for actions labels
|
||||
|
|
|
@ -292,7 +292,7 @@ export function naturalSort(a, b, lang) {
|
|||
}
|
||||
|
||||
export function sortFeatures(features, sortKey, lang) {
|
||||
const sortKeys = (sortKey || 'name').split(',')
|
||||
const sortKeys = sortKey.split(',')
|
||||
|
||||
const sort = (a, b, i) => {
|
||||
let sortKey = sortKeys[i]
|
||||
|
|
|
@ -15,7 +15,12 @@ DATALAYER_DATA = {
|
|||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {"name": "one point in france", "foo": "point", "bar": "one"},
|
||||
"properties": {
|
||||
"name": "one point in france",
|
||||
"foo": "point",
|
||||
"bar": "one",
|
||||
"label": "this is label one",
|
||||
},
|
||||
"geometry": {"type": "Point", "coordinates": [3.339844, 46.920255]},
|
||||
},
|
||||
{
|
||||
|
@ -24,6 +29,7 @@ DATALAYER_DATA = {
|
|||
"name": "one polygon in greenland",
|
||||
"foo": "polygon",
|
||||
"bar": "two",
|
||||
"label": "this is label two",
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
|
@ -44,6 +50,7 @@ DATALAYER_DATA = {
|
|||
"name": "one line in new zeland",
|
||||
"foo": "line",
|
||||
"bar": "three",
|
||||
"label": "this is label three",
|
||||
},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
|
@ -476,3 +483,11 @@ def test_main_toolbox_toggle_all_layers(live_server, map, page):
|
|||
# Should hidden again all layers
|
||||
expect(page.locator(".datalayer.off")).to_have_count(3)
|
||||
expect(markers).to_have_count(0)
|
||||
|
||||
|
||||
def test_honour_the_label_fields_settings(live_server, map, page, bootstrap, settings):
|
||||
settings.UMAP_LABEL_KEYS = ["label", "name"]
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
expect(page.locator(".panel").get_by_text("this is label one")).to_be_visible()
|
||||
expect(page.locator(".panel").get_by_text("this is label two")).to_be_visible()
|
||||
expect(page.locator(".panel").get_by_text("this is label three")).to_be_visible()
|
||||
|
|
|
@ -609,6 +609,7 @@ class MapDetailMixin(SessionMixin):
|
|||
"websocketEnabled": settings.WEBSOCKET_ENABLED,
|
||||
"websocketURI": settings.WEBSOCKET_FRONT_URI,
|
||||
"importers": settings.UMAP_IMPORTERS,
|
||||
"defaultLabelKeys": settings.UMAP_LABEL_KEYS,
|
||||
}
|
||||
created = bool(getattr(self, "object", None))
|
||||
if (created and self.object.owner) or (not created and not user.is_anonymous):
|
||||
|
|
Loading…
Reference in a new issue