Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
269d1ad
perf(forms): select2
submarcos Nov 13, 2025
fa48649
perf(api): improve zoning
submarcos Nov 14, 2025
fd462b4
Merge branch 'master' into perfs_select
submarcos Nov 17, 2025
9962426
Fix translation files
submarcos Nov 17, 2025
c1fc142
perf(index): add index on searched fields
submarcos Nov 17, 2025
8cccb28
perf(index): add index on searched fields
submarcos Nov 17, 2025
32bcf1b
Merge branch 'master' into perfs_select
submarcos Nov 17, 2025
7c063ad
test(feat): feat tests
submarcos Nov 17, 2025
2746688
test(factory): fix choices
submarcos Nov 18, 2025
a97dc51
test(factory): fix choices
submarcos Nov 18, 2025
289054b
test(factory): fix choices
submarcos Nov 18, 2025
cf99655
test(factory): fix choices
submarcos Nov 18, 2025
9d42fa0
test(factory): fix choices
submarcos Nov 18, 2025
d9510c9
Fix translation files
submarcos Nov 18, 2025
11cf49d
test(factory): fix choices
submarcos Nov 18, 2025
d953d97
test(factory): fix choices
submarcos Nov 18, 2025
e6e6fdd
test(factory): fix choices
submarcos Nov 18, 2025
b1232a0
test(factory): fix choices
submarcos Nov 18, 2025
7d609a3
feat(autocomplete): enhance filtering by id and query parameters
submarcos Nov 24, 2025
68a8ce6
feat(autocomplete): implement autocomplete functionality for city and…
submarcos Nov 24, 2025
929c58a
Merge branch 'master' into perfs_select
submarcos Nov 24, 2025
8d64df2
test(forms): add tests for MapFilterForm field presence and validation
submarcos Nov 25, 2025
7c74969
refactor(autocomplete): streamline AutocompleteMixin by removing redu…
submarcos Nov 25, 2025
da8cb0e
test(models): add test for signage display in Blade model
submarcos Nov 25, 2025
683f142
Fix deps
submarcos Nov 25, 2025
33a4cc3
fix(models): correct signage title translation in signage_display pro…
submarcos Nov 26, 2025
e34fb27
fix(models): correct signage title translation in signage_display pro…
submarcos Nov 26, 2025
bf7c93a
fix(models): correct signage title translation in signage_display pro…
submarcos Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ coverage:
rm ./var/.coverage*

test:
$(docker_compose) run -e ENV=tests --rm web ./manage.py test --shuffle --noinput --parallel
$(docker_compose) run -e ENV=tests --rm web ./manage.py test $(test_name) --shuffle --noinput --parallel

test_nds:
$(docker_compose) run -e ENV=tests_nds --rm web ./manage.py test --shuffle --noinput --parallel
$(docker_compose) run -e ENV=tests_nds --rm web ./manage.py test $(test_name) --shuffle --noinput --parallel

tests: test test_nds

Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/nav_create_signage.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('Create signage', () => {
cy.get("input[name='name_en']").type('Signage number 1')
cy.get("a[href='#name_fr']").click()
cy.get("input[name='name_fr']").type('Signalétique numéro 1')
cy.get("select[id='id_type']").select("Service")
cy.get("select[id='id_type']").select("Service", { force: true })
cy.get('#save_changes').click()
cy.url().should('not.include', '/signage/add/')
})
Expand Down
6 changes: 3 additions & 3 deletions cypress/integration/nav_create_trek.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ describe('Create trek', () => {
cy.get("a[href='#arrival_fr']").click();
cy.get("input[id='id_arrival_fr']").type('Arrivée');
cy.get("input[id='id_duration']").type('100');
cy.get("select[id='id_practice']").select("Cycling");
cy.get("select[id='id_difficulty']").select("Very hard");
cy.get("select[id='id_route']").select("Loop");
cy.get("select[id='id_practice']").select("Cycling", { force: true });
cy.get("select[id='id_difficulty']").select("Very hard", { force: true });
cy.get("select[id='id_route']").select("Loop", { force: true });
cy.setTinyMceContent('id_access_en', 'Access number 1');;
cy.setTinyMceContent('id_description_teaser_en', 'Description teaser number 1');
cy.setTinyMceContent('id_ambiance_en', 'Ambiance number 1');
Expand Down
22 changes: 11 additions & 11 deletions cypress/integration/nav_reports_workflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ describe('Nav reports workflow', () => {
cy.get("#id_message_administrators").should("not.be.visible")
cy.get("#id_message_supervisor").should("not.be.visible")
// Change selected status to resolved
cy.get("#id_status").select("3")
cy.get("#id_status").select("3", { force: true })
// Can use selectors for sentinel messages
cy.get("#id_message_sentinel_predefined").should("be.visible")
cy.get("#id_message_sentinel").should("be.visible")
cy.get("#id_message_administrators").should("be.visible")
cy.get("#id_message_supervisor").should("not.be.visible")
// Select a predefined email
cy.get("#id_message_sentinel_predefined").select("1")
cy.get("#id_message_sentinel_predefined").select("1", { force: true })
cy.get("#id_message_sentinel").should("have.value", "Pris en charge par Comm des Comm des Arbres Binaires le 17/05/2022")
cy.get("#id_message_administrators").should("have.value", "Pris en charge par Comm des Comm des Arbres Binaires le 17/05/2022")
// Remove predefined email
cy.get("#id_message_sentinel_predefined").select("")
cy.get("#id_message_sentinel_predefined").select("", { force: true })
cy.get("#id_message_sentinel").should("have.value", "")
cy.get("#id_message_administrators").should("have.value", "")
// Change selected status back to initial one
cy.get("#id_status").select("1")
cy.get("#id_status").select("1", { force: true })
// Cannot use selectors for sentinel and supervisor messages anymore
cy.get("#id_message_sentinel_predefined").should("not.be.visible")
cy.get("#id_message_sentinel").should("not.be.visible")
Expand All @@ -55,37 +55,37 @@ describe('Nav reports workflow', () => {
cy.get("#id_message_administrators").should("not.be.visible")
cy.get("#id_message_supervisor").should("not.be.visible")
// Change selected status to waiting
cy.get("#id_status").select("4")
cy.get("#id_status").select("4", { force: true })
// Select an assigned user
cy.get("#id_current_user").select("5")
cy.get("#id_current_user").select("5", { force: true })
// Can use selectors for sentinel and supervisor messages
cy.get("#id_message_sentinel_predefined").scrollIntoView().should("be.visible")
cy.get("#id_message_sentinel").scrollIntoView().should("be.visible")
cy.get("#id_message_administrators").scrollIntoView().should("be.visible")
cy.get("#id_message_supervisor").scrollIntoView().should("be.visible")
cy.get("#modelfields").scrollTo('bottom').get("#id_message_supervisor").should("be.visible")
// Select a predefined email
cy.get("#id_message_sentinel_predefined").select("2")
cy.get("#id_message_sentinel_predefined").select("2", { force: true })
cy.get("#id_message_sentinel").should("have.value", "Faire attention a la marche")
cy.get("#id_message_administrators").should("have.value", "Faire attention a la marche")
cy.get("#id_message_supervisor").should("have.value", "")
// Select another predefined email
cy.get("#id_message_sentinel_predefined").select("3")
cy.get("#id_message_sentinel_predefined").select("3", { force: true })
cy.get("#id_message_sentinel").should("have.value", "Ce probleme n'en sera bientot plus un")
cy.get("#id_message_administrators").should("have.value", "Ce probleme n'en sera bientot plus un")
// Select another assigned user
cy.get("#id_current_user").select("1")
cy.get("#id_current_user").select("1", { force: true })
// Can use selectors for sentinel and supervisor messages
cy.get("#id_message_sentinel_predefined").scrollIntoView().should("be.visible")
cy.get("#id_message_sentinel").scrollIntoView().should("be.visible")
cy.get("#id_message_administrators").scrollIntoView().should("be.visible")
cy.get("#modelfields").scrollTo('bottom').get("#id_message_supervisor").should("be.visible")
// Remove predefined email
cy.get("#id_message_sentinel_predefined").select("")
cy.get("#id_message_sentinel_predefined").select("", { force: true })
cy.get("#id_message_sentinel").should("have.value", "")
cy.get("#id_message_administrators").should("have.value", "")
// Change status back
cy.get("#id_status").select("2")
cy.get("#id_status").select("2", { force: true })
// Cannot use selectors for sentinel and supervisor messages anymore
cy.get("#id_message_sentinel_predefined").should("not.be.visible")
cy.get("#id_message_sentinel").should("not.be.visible")
Expand Down
13 changes: 7 additions & 6 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ FROM base AS build

USER root

RUN apt-get update -qq && apt-get install -y -qq \
git \
build-essential \
graphviz \
libpq-dev &&\
apt-get clean all && rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apt/*
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update -qq && apt-get install -y -qq \
git \
build-essential \
graphviz \
libpq-dev

USER geotrek

Expand Down
4 changes: 2 additions & 2 deletions geotrek/altimetry/filters.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.utils.translation import gettext_lazy as _
from django_filters import FilterSet
from mapentity.filters import MapEntityFilterSet

from geotrek.common.filters import OptionalRangeFilter


class AltimetryPointFilterSet(FilterSet):
class AltimetryPointFilterSet(MapEntityFilterSet):
elevation = OptionalRangeFilter(label=_("elevation"), method="filter_elevation")

def filter_elevation(self, qs, name, value):
Expand Down
8 changes: 6 additions & 2 deletions geotrek/api/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,10 @@ def get_elevation(self, obj):
return obj.species.radius

def get_species_id(self, obj):
if obj.species.category == sensitivity_models.Species.SPECIES:
if (
obj.species.category
== sensitivity_models.Species.CategoryChoices.SPECIES
):
return obj.species_id
return None

Expand Down Expand Up @@ -1346,7 +1349,8 @@ class BubbleSensitiveAreaSerializer(SensitiveAreaSerializer):

def get_radius(self, obj):
if (
obj.species.category == sensitivity_models.Species.SPECIES
obj.species.category
== sensitivity_models.Species.CategoryChoices.SPECIES
and obj.geom.geom_typeid == 0
):
return obj.species.radius
Expand Down
4 changes: 3 additions & 1 deletion geotrek/common/filters/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ def to_python(self, value):


class OneLineRangeField(RangeField):
widget = OneLineRangeWidget(attrs={"class": "minmax-field"})
widget = OneLineRangeWidget(
attrs={"class": "minmax-field form-control form-control-sm"}
)
18 changes: 17 additions & 1 deletion geotrek/common/mixins/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import uuid

from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.gis.db.models.functions import Envelope, Transform
from django.core.files.storage import default_storage
from django.core.mail import mail_managers
from django.db import models
from django.db.models import Count, Max
from django.template import Context, Template
from django.template.defaultfilters import slugify
Expand Down Expand Up @@ -512,3 +513,18 @@ def get_eid(self):
"{% load i18n %} <span class='none'>{% trans 'None' %}</span>"
)
return mark_safe(tmpl.render(Context({})))


class BBoxMixin(models.Model):
envelope = models.GeneratedField(
expression=Envelope(Transform("geom", settings.API_SRID)),
db_persist=True,
output_field=models.GeometryField(),
)

@property
def bbox(self):
return self.envelope.extent

class Meta:
abstract = True
7 changes: 7 additions & 0 deletions geotrek/common/static/common/style.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#mainfilter input.minmax-field {
width: calc(60% - 1.9rem);
border-radius: 1px !important;

}

#mainfilter .form-row {
margin-right: 0 !important;
margin-left: 0 !important;
}

.caption-detail {
Expand Down
2 changes: 1 addition & 1 deletion geotrek/common/templates/common/range_widget.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}- {% endif %}{% endfor %}
<div class="form-row align-items-center">{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}&nbsp;-&nbsp;{% endif %}{% endfor %}</div>
45 changes: 30 additions & 15 deletions geotrek/core/filters.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from dal import autocomplete
from django.conf import settings
from django.db.models import Count, F, Q
from django.forms import widgets
from django.utils.translation import gettext_lazy as _
from django_filters import (
BooleanFilter,
CharFilter,
FilterSet,
ModelMultipleChoiceFilter,
)
Expand All @@ -27,10 +28,18 @@ class ValidTopologyFilterSet(FilterSet):

if settings.TREKKING_TOPOLOGY_ENABLED:
is_valid_topology = BooleanFilter(
label=_("Valid topology"), method="filter_valid_topology"
label=_("Valid topology"),
method="filter_valid_topology",
widget=widgets.NullBooleanSelect(
attrs={"class": "form-control form-control-sm"}
),
)
is_valid_geometry = BooleanFilter(
label=_("Valid geometry"), method="filter_valid_geometry"
label=_("Valid geometry"),
method="filter_valid_geometry",
widget=widgets.NullBooleanSelect(
attrs={"class": "form-control form-control-sm"}
),
)

def filter_valid_topology(self, qs, name, value):
Expand Down Expand Up @@ -124,26 +133,30 @@ def _topology_filter(self, qs, edges):
class PathFilterSet(
AltimetryAllGeometriesFilterSet, ZoningFilterSet, StructureRelatedFilterSet
):
name = CharFilter(label=_("Name"), lookup_expr="icontains")
comments = CharFilter(label=_("Comments"), lookup_expr="icontains")
provider = ModelMultipleChoiceFilter(
label=_("Provider"),
queryset=Provider.objects.filter(path__isnull=False).distinct(),
widget=autocomplete.Select2Multiple(),
)
networks = ModelMultipleChoiceFilter(
queryset=Network.objects.all().select_related("structure")
queryset=Network.objects.all().select_related("structure"),
widget=autocomplete.Select2Multiple(),
)
usages = ModelMultipleChoiceFilter(
queryset=Usage.objects.all().select_related("structure")
queryset=Usage.objects.all().select_related("structure"),
widget=autocomplete.Select2Multiple(),
)
comfort = ModelMultipleChoiceFilter(
queryset=Comfort.objects.all().select_related("structure")
queryset=Comfort.objects.all().select_related("structure"),
widget=autocomplete.Select2Multiple(),
)

class Meta(StructureRelatedFilterSet.Meta):
model = Path
fields = [
*StructureRelatedFilterSet.Meta.fields,
"name",
"comments",
"valid",
"networks",
"usages",
Expand All @@ -160,20 +173,16 @@ class TrailFilterSet(
ZoningFilterSet,
StructureRelatedFilterSet,
):
"""Trail filter set"""

name = CharFilter(label=_("Name"), lookup_expr="icontains")
departure = CharFilter(label=_("Departure"), lookup_expr="icontains")
arrival = CharFilter(label=_("Arrival"), lookup_expr="icontains")
comments = CharFilter(label=_("Comments"), lookup_expr="icontains")
certification_labels = ModelMultipleChoiceFilter(
field_name="certifications__certification_label",
label=_("Certification labels"),
queryset=CertificationLabel.objects.all(),
widget=autocomplete.Select2Multiple(),
)
provider = ModelMultipleChoiceFilter(
label=_("Provider"),
queryset=Provider.objects.filter(trail__isnull=False).distinct(),
widget=autocomplete.Select2Multiple(),
)

class Meta(StructureRelatedFilterSet.Meta):
Expand All @@ -197,5 +206,11 @@ class TopologyFilterTrail(TopologyFilter):
if settings.TRAIL_MODEL_ENABLED:
for filterset in (PathFilterSet, InterventionFilterSet, ProjectFilterSet):
filterset.add_filters(
{"trail": TopologyFilterTrail(label=_("Trail"), required=False)}
{
"trail": TopologyFilterTrail(
label=_("Trail"),
required=False,
widget=autocomplete.Select2Multiple(),
)
}
)
26 changes: 13 additions & 13 deletions geotrek/core/locale/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-23 11:11+0200\n"
"POT-Creation-Date: 2025-11-17 09:32+0000\n"
"PO-Revision-Date: 2025-10-22 09:00+0000\n"
"Last-Translator: Anonymous <[email protected]>\n"
"Language-Team: German <https://weblate.makina-corpus.net/projects/geotrek-admin/core/de/>\n"
Expand Down Expand Up @@ -43,21 +43,9 @@ msgstr ""
msgid "Valid geometry"
msgstr ""

msgid "Name"
msgstr ""

msgid "Comments"
msgstr ""

msgid "Provider"
msgstr ""

msgid "Departure"
msgstr ""

msgid "Arrival"
msgstr ""

msgid "Certification labels"
msgstr ""

Expand Down Expand Up @@ -115,15 +103,27 @@ msgstr ""
msgid "Shown in lists and maps"
msgstr ""

msgid "Name"
msgstr ""

msgid "Official name"
msgstr ""

msgid "Comments"
msgstr ""

msgid "Remarks"
msgstr ""

msgid "Departure"
msgstr ""

msgid "Departure place"
msgstr ""

msgid "Arrival"
msgstr ""

msgid "Arrival place"
msgstr ""

Expand Down
Loading