Skip to content

Commit 3ef29a0

Browse files
committed
Merge branch 'feature_objects_map' into 'main'
feat(map): UX improvements — filter buttons, list sync, overlap popup See merge request 701/netbox/cesnet_service_path_plugin!60
2 parents 72542a3 + e625753 commit 3ef29a0

9 files changed

Lines changed: 465 additions & 137 deletions

File tree

CHANGELOG.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,67 @@
11
# Changelog
22

3+
## [6.2.0] - 2026-04-27
4+
5+
### Added
6+
7+
- **Network Map — Tag filters**: Tag filter dropdowns added for Sites, Segments, and Circuits.
8+
Filtering uses AND logic — an object must carry all selected tags to match.
9+
- **Network Map — Object selection highlight**: Clicking a segment, circuit, or site now
10+
highlights the selected object on the map in orange. Highlight is restored when another
11+
object is selected or the info card is closed.
12+
- **Network Map — Tag colors in info card**: Tag badges in the detail info card now use the
13+
tag's configured color (with automatic light/dark contrast text).
14+
- **Network Map — Object list panel**: A second "List" tab in the right panel provides a
15+
searchable, scrollable list of all visible objects with type toggles and click-to-locate.
16+
- **Network Map — Filter sidebar**: Permanent right-side filter column replaces the offcanvas
17+
sidebar. Includes two "Clear Filters" buttons (top and bottom of the column).
18+
- **Network Map — Circuit termination details**: Info card shows cable connection, cross-connect
19+
ID, port speed, and a "Connect" dropdown button for unconnected terminations.
20+
21+
### Changed
22+
23+
- **Network Map — Status/type filter buttons**: Reverted from `<select multiple>` dropdowns
24+
back to btn-check pill buttons following user testing feedback. Button sizing reduced
25+
(0.65 rem, 20 px height) using flexbox to eliminate Bootstrap padding asymmetry.
26+
- **Network Map — Map popup links**: Plain text links in segment, circuit, and site popups
27+
replaced with `btn-outline` buttons (View / Map) for better discoverability.
28+
- **Network Map — Overlap popup**: Added `<hr>` separators between entries and View/Map
29+
buttons per segment. Segment names styled as blue links with hover underline and a
30+
"Click a name to show details" subtitle.
31+
- **Network Map — Object list sync**: List type buttons (Sites / Segs / Circs) now mirror
32+
the state of the main toolbar visibility toggles. List count and rows update immediately
33+
when toolbar toggles change. Circuits list button starts unchecked to match default
34+
hidden state.
35+
- **Network Map — Map height**: Increased to 1000 px for better usability on larger screens.
36+
- **Network Map — Color palette**: Segment and circuit colors updated to avoid green tones
37+
that blend with OSM map background.
38+
39+
### Fixed
40+
41+
- **Network Map — Object list initial count**: List now populates via `applyFilters()` on
42+
first load so counts reflect server-side pre-filters (e.g. region in URL) immediately.
43+
- **Network Map — List visibility respect**: Object list respects layer visibility flags;
44+
hidden layers are excluded from the list count and rows.
45+
- **Network Map — Segment popup midpoint**: When selecting a segment from the list, the
46+
popup now anchors to the middle vertex of the actual rendered GeoJSON polyline instead
47+
of the midpoint between the two endpoint sites.
48+
- **Network Map — Clear Filters Tom Select**: Region and other dynamic fields (Tom Select
49+
widgets) are now correctly cleared via `sel.tomselect.clear()` / `clearOptions()`.
50+
- **Network Map — Nav-tabs dark theme**: Switched from `nav-tabs` to `nav-pills` for the
51+
Filters / List tab switcher so tab labels are visible in NetBox dark mode.
52+
- **Network Map — Toggle button padding**: Fixed uneven top/bottom padding on btn-check
53+
filter pill buttons caused by Bootstrap `--bs-btn-padding-y` override.
54+
55+
### Compatibility
56+
57+
| cesnet_service_path_plugin | NetBox |
58+
|---|---|
59+
| 6.2.x | 4.5.4+ |
60+
| 6.1.x | 4.5.4+ |
61+
| 6.0.x | 4.5.0 – 4.5.3 |
62+
63+
---
64+
365
## [6.1.1] - 2026-03-19
466

567
### Fixed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ The CESNET ServicePath Plugin extends NetBox's capabilities by providing compreh
4747

4848
| NetBox Version | Plugin Version | Notes |
4949
|----------------|----------------|-------|
50+
| 4.5.4+ | 6.2.x | Network Map UX overhaul, tag filters, object highlight |
5051
| 4.5.4+ | 6.1.x | Requires NetBox >= 4.5.4 (strawberry-graphql-django >= 0.79.0) |
5152
| 4.5.0–4.5.3 | 6.0.x | **Breaking change**: Filter system updated, NOT compatible with 4.4.x |
5253
| 4.4.x | 5.4.x | Last version compatible with NetBox 4.4.x |
@@ -133,6 +134,12 @@ The CESNET ServicePath Plugin extends NetBox's capabilities by providing compreh
133134
- **Fallback visualization** showing straight lines when path data unavailable
134135
- **Overlapping segment detection** and selection on maps
135136
- **Path data export** as GeoJSON for external use
137+
- **Network Map** (new in 6.0.0, enhanced in 6.2.0): combined Sites + Segments + Circuits view
138+
- Permanent right-side panel with filter sidebar and searchable object list
139+
- Tag filters for Sites, Segments, and Circuits
140+
- Object selection highlight — selected object shown in orange on the map
141+
- Clickable info card showing full object details including tag colors and circuit termination info
142+
- Filter pill buttons for status and type with instant client-side filtering
136143
- An example of a geographic service path visualized using the plugin:
137144
![Sample Service Path Map](./docs/sample_path.png)
138145

@@ -196,8 +203,8 @@ Before installing the plugin, ensure you have:
196203

197204
1. **PostgreSQL with PostGIS extension** (version 3.0 or higher recommended)
198205
2. **System libraries**: GDAL, GEOS, and PROJ runtime binaries
199-
3. **NetBox 4.5.4 or higher** (for plugin version 6.1.x)
200-
- **Important**: Plugin version 6.1.x requires NetBox >= 4.5.4 (ships with strawberry-graphql-django >= 0.79.0)
206+
3. **NetBox 4.5.4 or higher** (for plugin version 6.2.x)
207+
- **Important**: Plugin version 6.2.x requires NetBox >= 4.5.4 (ships with strawberry-graphql-django >= 0.79.0)
201208
- For NetBox 4.5.0–4.5.3, use plugin version 6.0.x
202209
- If you're running NetBox 4.4.x, use plugin version 5.4.x or earlier
203210

@@ -865,7 +872,7 @@ check_gis_environment()
865872

866873
The plugin adds a **Service Paths** menu with:
867874
- **Segments** - List and manage network segments with quick Add/Import buttons
868-
- **Segments Map** - Interactive map view of all segments
875+
- **Network Map** - Combined interactive map of Sites, Segments, and Circuits
869876
- **Service Paths** - Manage service path definitions with quick Add/Import buttons
870877
- **Contract Info** - Manage contracts with versioning support (new in 5.4.0)
871878
- **Mappings** - Relationship management tools with quick Add/Import buttons

cesnet_service_path_plugin/forms/map.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from dcim.choices import SiteStatusChoices
33
from dcim.models import Region, Site, SiteGroup
44
from django import forms
5+
from extras.models import Tag
56
from tenancy.models import Tenant
67
from utilities.forms.fields import DynamicModelMultipleChoiceField
78

@@ -17,11 +18,11 @@ class MapFilterForm(forms.Form):
1718
1819
Field naming convention:
1920
- Shared spatial fields: native filterset names (region_id, site_group_id, at_any_site)
20-
- Site-specific fields: site_ prefix (site_status, site_tenant_id)
21-
- Segment-specific fields: segment_ prefix (segment_status, segment_type, segment_provider_id)
21+
- Site-specific fields: site_ prefix (site_status, site_tenant_id, site_tag_id)
22+
- Segment-specific fields: segment_ prefix (segment_status, segment_type, segment_provider_id, segment_tag_id)
23+
- Circuit-specific fields: circuit_ prefix (circuit_status, circuit_type_id, circuit_provider_id, circuit_tag_id)
2224
23-
The view's _extract_*_params() helpers strip/remap these prefixes before
24-
passing GET params to each filterset.
25+
All filtering is performed client-side in object_map.js using the JSON data blob.
2526
"""
2627

2728
# -------------------------------------------------------------------------
@@ -50,13 +51,17 @@ class MapFilterForm(forms.Form):
5051
choices=SiteStatusChoices,
5152
required=False,
5253
label="Status",
53-
widget=forms.SelectMultiple(attrs={"class": "form-select form-select-sm", "size": "1"}),
5454
)
5555
site_tenant_id = DynamicModelMultipleChoiceField(
5656
queryset=Tenant.objects.all(),
5757
required=False,
5858
label="Tenant",
5959
)
60+
site_tag_id = DynamicModelMultipleChoiceField(
61+
queryset=Tag.objects.all(),
62+
required=False,
63+
label="Tag",
64+
)
6065

6166
# -------------------------------------------------------------------------
6267
# Segment filters
@@ -65,19 +70,22 @@ class MapFilterForm(forms.Form):
6570
choices=StatusChoices,
6671
required=False,
6772
label="Status",
68-
widget=forms.SelectMultiple(attrs={"class": "form-select form-select-sm", "size": "1"}),
6973
)
7074
segment_type = forms.MultipleChoiceField(
7175
choices=SegmentTypeChoices,
7276
required=False,
7377
label="Type",
74-
widget=forms.SelectMultiple(attrs={"class": "form-select form-select-sm", "size": "1"}),
7578
)
7679
segment_provider_id = DynamicModelMultipleChoiceField(
7780
queryset=Provider.objects.all(),
7881
required=False,
7982
label="Provider",
8083
)
84+
segment_tag_id = DynamicModelMultipleChoiceField(
85+
queryset=Tag.objects.all(),
86+
required=False,
87+
label="Tag",
88+
)
8189

8290
# -------------------------------------------------------------------------
8391
# Circuit filters
@@ -86,7 +94,6 @@ class MapFilterForm(forms.Form):
8694
choices=[], # populated in __init__ to avoid import-time issues
8795
required=False,
8896
label="Status",
89-
widget=forms.SelectMultiple(attrs={"class": "form-select form-select-sm", "size": "1"}),
9097
)
9198
circuit_type_id = DynamicModelMultipleChoiceField(
9299
queryset=CircuitType.objects.all(),
@@ -98,6 +105,11 @@ class MapFilterForm(forms.Form):
98105
required=False,
99106
label="Provider",
100107
)
108+
circuit_tag_id = DynamicModelMultipleChoiceField(
109+
queryset=Tag.objects.all(),
110+
required=False,
111+
label="Tag",
112+
)
101113

102114
def __init__(self, *args, **kwargs):
103115
super().__init__(*args, **kwargs)

0 commit comments

Comments
 (0)