Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@ Database Module
:undoc-members:
:show-inheritance:

Query Module
------------

Sorting, limiting, and query orchestration for location data.

.. automodule:: goodmap.core
:members:
:undoc-members:
:show-inheritance:

Filtering Module
----------------

Category filter combination logic (see :ref:`categories-filter-mode` in
:doc:`quickstart` for the config-level guide).

.. automodule:: goodmap.filtering
:members:
:undoc-members:
:show-inheritance:

API Endpoints
-------------

Expand Down
69 changes: 67 additions & 2 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Example configuration in your data source:
]
}

.. _categories-filter-mode:

Categories and Filtering
~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -92,24 +94,87 @@ checkboxes, one per allowed value.
pre-checked in the filter panel when the app first loads, before the user
has made any selection.

Example configuration in your data source:
``categories_filter_mode``
Dict of category key to how *multiple selected values within that
category* are combined when filtering locations. Categories not listed
here default to ``"or"``. This only affects combination **within** one
category - across different categories, selections are always combined
with AND (a location must match every category that has an active
selection).

``"or"`` (default)
A location matches if it has **any** of the selected values. This is
the usual "check more boxes to broaden results" behavior - e.g.
checking both ``bikes`` and ``cars`` on ``accessible_by`` shows
locations that allow bikes *or* cars, not only locations that allow
both (which would often be zero results).

``"and"``
A location matches only if it has **every** one of the selected
values - narrowing rather than broadening. Only meaningful for
list-valued categories (a location can have several simultaneous
values); for a single-valued category it behaves like ``"or"``
restricted to one selection at a time. Still rendered as checkboxes
(it's still multi-select), but with a "(match all)" hint next to the
category title so it reads differently from the default "or"
behavior - e.g. an ``amenities`` field where checking ``lighting``
and ``benches`` should show only bridges that have both, not either.

``"exclusive"``
Single-select: the frontend renders the options as radio buttons
instead of checkboxes, so only one value can be active at a time. Use
this for categories with three or more mutually-exclusive states,
e.g. a toll tier: ``free`` / ``discounted`` / ``full_price``.

``"boolean"``
For a field with exactly the two values ``"true"`` and ``"false"``.
Only the ``"true"`` option is rendered, as a single checkbox; leaving
it unchecked already means "show everything" (both true and false
locations), so there's no separate control for isolating ``"false"``
alone. Use this when nobody would deliberately filter for the
negative case - e.g. a "free only" checkbox for an ``is_free`` field,
since drivers care about "free" or "all", not "paid only".

``"threshold"``
For an ordered, numeric-valued category, e.g. a speed limit in km/h.
Selecting a value matches any location whose value is **at or below**
the highest selected value - e.g. selecting ``30`` also matches
locations with ``10`` or ``30``, but not ``50``. The frontend renders
this as radio buttons too, since selecting more than one option would
be redundant: the highest selection alone determines the cutoff.

Example configuration combining all five modes:

.. code-block:: json

{
"categories": {
"accessible_by": ["bikes", "cars", "pedestrians"],
"type_of_place": ["big bridge", "small bridge"]
"type_of_place": ["big bridge", "small bridge"],
"is_free": ["true", "false"],
"speed_limit": ["10", "30", "50"],
"amenities": ["lighting", "benches", "toilets"]
},
"categories_help": ["accessible_by"],
"categories_options_help": {
"accessible_by": ["cars", "pedestrians"]
},
"categories_default_checked": {
"accessible_by": ["cars"]
},
"categories_filter_mode": {
"accessible_by": "or",
"type_of_place": "or",
"is_free": "boolean",
"speed_limit": "threshold",
"amenities": "and"
}
}

The active mode for each category is also exposed as ``filter_mode`` in the
``/api/categories-full`` response, so a custom frontend can render the
right control (checkbox vs. radio) without hardcoding category names.

.. _data-model-visible_data:

Database Types
Expand Down
205 changes: 199 additions & 6 deletions e2e-tests/e2e_test_data_initial.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
{
"name": "Grunwaldzki",
"position": [
51.1095,
51.109444,
17.0525
],
"accessible_by": [
"pedestrians",
"cars"
],
"type_of_place": "big bridge",
"is_free": "true",
"speed_limit": "50",
"amenities": [
"lighting",
"benches"
],
"uuid": "9264286a-5d33-4e38-ab11-c8e179a7754a",
"CTA": {
"type": "CTA",
Expand All @@ -22,16 +28,166 @@
{
"name": "Zwierzyniecka",
"position": [
51.10655,
17.0555
51.108056,
17.07
],
"accessible_by": [
"bikes",
"pedestrians"
],
"type_of_place": "small bridge",
"is_free": "true",
"speed_limit": "10",
"amenities": [
"lighting"
],
"uuid": "c8ecf476-5968-40da-ba5c-e810ad9ff203",
"remark": "very old bridge"
},
{
"name": "Milenijny",
"position": [
51.133692,
16.993103
],
"accessible_by": [
"cars"
],
"type_of_place": "big bridge",
"is_free": "false",
"speed_limit": "30",
"amenities": [],
"uuid": "1a8f9a2e-4b6d-4a1a-9a8e-2f6c7d0b3e9a",
"remark": "toll bridge, cars only"
},
{
"name": "Pokoju",
"position": [
51.111739,
17.049236
],
"accessible_by": [
"cars",
"pedestrians"
],
"type_of_place": "big bridge",
"is_free": "true",
"speed_limit": "50",
"amenities": [
"lighting",
"benches",
"toilets"
],
"uuid": "f03afca0-4ef8-45bf-a176-dd477ce48d92"
},
{
"name": "Tumski",
"position": [
51.114708,
17.042319
],
"accessible_by": [
"pedestrians"
],
"type_of_place": "small bridge",
"is_free": "true",
"speed_limit": "10",
"amenities": [
"lighting",
"benches"
],
"uuid": "e8b8a5b2-91e1-49f9-821b-5c7fa9eceb4b",
"remark": "connects the cathedral island"
},
{
"name": "Piaskowy",
"position": [
51.113542,
17.039806
],
"accessible_by": [
"pedestrians"
],
"type_of_place": "small bridge",
"is_free": "true",
"speed_limit": "10",
"amenities": [
"benches"
],
"uuid": "5986e755-1eaa-4121-a01c-4fef1d5d1da1"
},
{
"name": "Uniwersytecki",
"position": [
51.11525,
17.033694
],
"accessible_by": [
"pedestrians"
],
"type_of_place": "small bridge",
"is_free": "true",
"speed_limit": "30",
"amenities": [
"lighting"
],
"uuid": "043dd6ed-1b70-40a1-a7ad-dbfa3424ed8e"
},
{
"name": "Redzinski",
"position": [
51.155556,
16.958889
],
"accessible_by": [
"cars"
],
"type_of_place": "big bridge",
"is_free": "false",
"speed_limit": "50",
"amenities": [
"lighting"
],
"uuid": "66847536-4ffb-452d-b03d-874831abb233",
"remark": "highway bridge, cars only"
},
{
"name": "Osobowicki",
"position": [
51.131389,
17.027778
],
"accessible_by": [
"cars",
"pedestrians"
],
"type_of_place": "big bridge",
"is_free": "true",
"speed_limit": "30",
"amenities": [
"lighting",
"benches"
],
"uuid": "1d7ff5c0-ea4d-4701-bf53-49295333e176"
},
{
"name": "Warszawski",
"position": [
51.130256,
17.059375
],
"accessible_by": [
"cars",
"pedestrians"
],
"type_of_place": "big bridge",
"is_free": "true",
"speed_limit": "50",
"amenities": [
"lighting",
"toilets"
],
"uuid": "e77cac7f-78ba-4a6d-8d99-8018c5057de6"
}
],
"location_obligatory_fields": [
Expand All @@ -46,6 +202,18 @@
[
"type_of_place",
"str"
],
[
"is_free",
"str"
],
[
"speed_limit",
"str"
],
[
"amenities",
"list"
]
],
"reported_issue_types": [
Expand All @@ -62,10 +230,33 @@
"type_of_place": [
"big bridge",
"small bridge"
],
"is_free": [
"true",
"false"
],
"speed_limit": [
"10",
"30",
"50"
],
"amenities": [
"lighting",
"benches",
"toilets"
]
},
"categories_filter_mode": {
"accessible_by": "or",
"type_of_place": "or",
"is_free": "boolean",
"speed_limit": "threshold",
"amenities": "and"
},
"categories_help": [
"accessible_by"
"accessible_by",
"speed_limit",
"amenities"
],
"categories_options_help": {
"type_of_place": [
Expand All @@ -85,6 +276,9 @@
"remark",
"accessible_by",
"type_of_place",
"is_free",
"speed_limit",
"amenities",
"CTA"
],
"meta_data": [
Expand Down Expand Up @@ -153,7 +347,6 @@
"url": "https://fonts.googleapis.com/css2?family=Poppins"
},
"primary_color": "#FFFFFF",
"secondary_color": "#245466",
"left_bar_width": "300px"
"secondary_color": "#245466"
}
}
1 change: 0 additions & 1 deletion e2e-tests/scripts/generate_stress_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def main():
},
"primary_color": "#FFFFFF",
"secondary_color": "#245466",
"left_bar_width": "300px",
},
}

Expand Down
Loading
Loading