Closes #64: Show neighbors option (#286)

* Add option to show neighbors

* Updated documentation and help text

* Added newlines at end of files where they where missing

* Updated options screenshot

* fix function vars

---------
This commit is contained in:
Mario
2023-04-30 19:09:36 +02:00
committed by GitHub
parent 5e9aaecf9c
commit 5c58f2a9c2
8 changed files with 119 additions and 40 deletions
+5 -3
View File
@@ -99,15 +99,13 @@ Go to the plugins tab in the navbar and click topology or go to `$NETBOX_URL/plu
Select your options for the topology view:
![selection_options](https://user-images.githubusercontent.com/20901110/220410144-5633d24c-6383-4cba-8d6d-ba77ef3d3cdd.png)
![topology_options](https://user-images.githubusercontent.com/20901110/235302073-234c3ef7-2c2b-4d0c-a674-9909d490d7ea.png)
<dl>
<dt>Save Coordinates</dt>
<dd>Save the coordinates of devices in the topology view.</dd>
<dt>Show Unconnected</dt>
<dd>Show devices that have no connections or for which no connection is displayed. This option depends on other parameters like 'Show Cables' and 'Show Logical Connections'.</dd>
<dt>Show Circuit Terminations</dt>
<dd>Show connections which end at a circuit termination in the topology view. These connections are displayed as blue dashed lines.</dd>
<dt>Show Cables</dt>
<dd>Show connections between interfaces, front / rear ports, etc., that are connected with one or more cables. These connections are displayed as solid lines in the color of the cable.</dd>
<dt>Show Logical Connections</dt>
@@ -116,6 +114,10 @@ Select your options for the topology view:
intermediate front / rear port connections, etc. This is similar to what was referred to as 'end-to-end' connections in previous versions. These connections are displayed as yellow dotted lines.</dd>
<dt>Show redundant Cable and Locigal Connection</dt>
<dd>Shows a logical connection (in addition to a cable), even if a cable is directly connected. Leaving this option disabled prevents that redundant display. This option only has an effect if 'Show Logical Connections' is activated.</dd>
<dt>Show Neighbors</dt>
<dd>Adds neighbors to the filter result set automatically. Link peers will be added if 'Show Cables' is ticked, far-end terminations will be added if 'Show Logical Connections' is ticked.</dd>
<dt>Show Circuit Terminations</dt>
<dd>Show connections which end at a circuit termination in the topology view. These connections are displayed as blue dashed lines.</dd>
<dt>Show Power Feeds</dt>
<dd>Displays connections between power outlets and power ports. These connections are displayed as solid lines in the color of the cable. This option depends on 'Show Cables'.</dd>
<dt>Show Wireless Links</dt>
+2 -1
View File
@@ -25,4 +25,5 @@ class DeviceRoleSerializer(ModelSerializer):
class IndividualOptionsSerializer(NetBoxModelSerializer):
class Meta:
model = IndividualOptions
fields = ("ignore_cable_type", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_circuit", "show_power", "show_wireless", "draw_default_layout")
fields = ("ignore_cable_type", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_neighbors", "show_circuit", "show_power", "show_wireless", "draw_default_layout")
+21 -15
View File
@@ -80,23 +80,29 @@ class ExportTopoToXML(PermissionRequiredMixin, ViewSet):
user_id=request.user.id,
)
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless = get_query_settings(request)
topo_data = get_topology_data(
self.queryset,
individualOptions,
show_unconnected,
save_coords,
show_cables,
show_circuit,
show_logical_connections,
show_single_cable_logical_conns,
show_power,
show_wireless,
)
xml_data = export_data_to_xml(topo_data).decode('utf-8')
if request.GET:
return HttpResponse(xml_data, content_type="application/xml; charset=utf-8")
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors = get_query_settings(request)
topo_data = get_topology_data(
queryset=self.queryset,
individualOptions=individualOptions,
save_coords=save_coords,
show_unconnected=show_unconnected,
show_cables=show_cables,
show_logical_connections=show_logical_connections,
show_single_cable_logical_conns=show_single_cable_logical_conns,
show_neighbors=show_neighbors,
show_circuit=show_circuit,
show_power=show_power,
show_wireless=show_wireless,
)
xml_data = export_data_to_xml(topo_data).decode('utf-8')
return HttpResponse(xml_data, content_type="application/xml; charset=utf-8")
else:
return JsonResponse(
{"status": "Missing or malformed request parameters"}, status=400
)
class SaveRoleImageViewSet(PermissionRequiredMixin, ViewSet):
queryset = DeviceRole.objects.none()
+23 -9
View File
@@ -33,9 +33,10 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
"save_coords",
"show_unconnected",
"show_cables",
"show_circuit",
"show_logical_connections",
"show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power",
"show_wireless",
),
@@ -118,17 +119,17 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
show_unconnected = forms.BooleanField(
label=_("Show Unconnected"), required=False, initial=False
)
show_cables = forms.BooleanField(
label =_("Show Cables"), required=False, initial=False
)
show_logical_connections = forms.BooleanField(
label =_("Show Logical Connections"), required=False, initial=False
)
show_single_cable_logical_conns = forms.BooleanField(
label =_("Show redundant Cable and Locigal Connection"), required=False, initial=False
)
show_cables = forms.BooleanField(
label =_("Show Cables"), required=False, initial=False
)
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"), required=False, initial=False
show_neighbors = forms.BooleanField(
label =_("Show Neighbors"), required=False, initial=False
)
show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"), required=False, initial=False
@@ -136,6 +137,9 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
show_power = forms.BooleanField(
label=_("Show Power Feeds"), required=False, initial=False
)
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"), required=False, initial=False
)
class IndividualOptionsForm(NetBoxModelForm):
fieldsets = (
@@ -148,9 +152,10 @@ class IndividualOptionsForm(NetBoxModelForm):
"preselected_tags",
"show_unconnected",
"show_cables",
"show_circuit",
"show_logical_connections",
"show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power",
"show_wireless",
"draw_default_layout",
@@ -215,6 +220,14 @@ class IndividualOptionsForm(NetBoxModelForm):
"disabled prevents that redundant display. This option only "
"has an effect if 'Show Logical Connections' is activated.")
)
show_neighbors = forms.BooleanField(
label =_("Show Neighbors"),
required=False,
initial=False,
help_text=_("Adds neighbors to the filter result set automatically. "
"Link peers will be added if 'Show Cables' is ticked, far-end "
"terminations will be added if 'Show Logical Connections' is ticked.")
)
show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"),
required=False,
@@ -248,5 +261,6 @@ class IndividualOptionsForm(NetBoxModelForm):
class Meta:
model = IndividualOptions
fields = [
'user_id', 'ignore_cable_type', 'preselected_device_roles', 'preselected_tags', 'show_unconnected', 'show_cables', 'show_logical_connections', 'show_single_cable_logical_conns', 'show_circuit', 'show_power', 'show_wireless', 'draw_default_layout'
]
'user_id', 'ignore_cable_type', 'preselected_device_roles', 'preselected_tags', 'show_unconnected', 'show_cables', 'show_logical_connections', 'show_single_cable_logical_conns', 'show_neighbors', 'show_circuit', 'show_power', 'show_wireless', 'draw_default_layout'
]
@@ -0,0 +1,18 @@
# Generated by Django 4.1.8 on 2023-04-29 09:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('netbox_topology_views', '0002_individualoptions'),
]
operations = [
migrations.AddField(
model_name='individualoptions',
name='show_neighbors',
field=models.BooleanField(default=False),
),
]
+3
View File
@@ -137,6 +137,9 @@ class IndividualOptions(NetBoxModel):
show_single_cable_logical_conns = models.BooleanField(
default=False
)
show_neighbors = models.BooleanField(
default=False
)
show_circuit = models.BooleanField(
default=False
)
+6 -1
View File
@@ -154,8 +154,13 @@ def get_query_settings(request):
if "show_wireless" in request.GET:
if request.GET["show_wireless"] == "on" :
show_wireless = True
show_neighbors = False
if "show_neighbors" in request.GET:
if request.GET["show_neighbors"] == "on" :
show_neighbors = True
return save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless
return save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors
class LinePattern():
wireless = [2, 10, 2, 10]
+41 -11
View File
@@ -2,6 +2,7 @@ import json
from functools import reduce
from typing import DefaultDict, Dict, Optional, Union
import time
from itertools import chain
from utilities.htmx import is_htmx
from circuits.models import Circuit, CircuitTermination
@@ -263,6 +264,7 @@ def get_topology_data(
show_circuit: bool,
show_logical_connections: bool,
show_single_cable_logical_conns: bool,
show_neighbors: bool,
show_power: bool,
show_wireless: bool,
):
@@ -290,6 +292,31 @@ def get_topology_data(
device_ids = [d.pk for d in queryset]
site_ids = [d.site_id for d in queryset]
if show_neighbors:
interfaces = Interface.objects.filter(
Q(device_id__in=device_ids)
)
frontports = FrontPort.objects.filter(
Q(device_id__in=device_ids)
)
rearports = RearPort.objects.filter(
Q(device_id__in=device_ids)
)
ports = chain(interfaces, frontports, rearports)
for port in ports:
for link_peer in port.link_peers:
if link_peer.device.id not in device_ids:
device_ids.append(link_peer.device.id)
if show_logical_connections:
path_complete_interfaces = Interface.objects.filter(
Q(_path__is_complete=True) & Q(device_id__in=device_ids)
)
for path_complete_interface in path_complete_interfaces:
for connected_endpoint in path_complete_interface.connected_endpoints:
device_ids.append(connected_endpoint.device.id)
if show_circuit:
circuit_terminations = CircuitTermination.objects.filter(
Q(site_id__in=site_ids) | Q(provider_network__isnull=False)
@@ -600,20 +627,21 @@ class TopologyHomeView(PermissionRequiredMixin, View):
if request.GET:
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless = get_query_settings(request)
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors = get_query_settings(request)
if not "draw_init" in request.GET or "draw_init" in request.GET and request.GET["draw_init"].lower() == "true":
topo_data = get_topology_data(
self.queryset,
individualOptions,
show_unconnected,
save_coords,
show_cables,
show_circuit,
show_logical_connections,
show_single_cable_logical_conns,
show_power,
show_wireless,
queryset=self.queryset,
individualOptions=individualOptions,
save_coords=save_coords,
show_unconnected=show_unconnected,
show_cables=show_cables,
show_logical_connections=show_logical_connections,
show_single_cable_logical_conns=show_single_cable_logical_conns,
show_neighbors=show_neighbors,
show_circuit=show_circuit,
show_power=show_power,
show_wireless=show_wireless,
)
else:
@@ -629,6 +657,7 @@ class TopologyHomeView(PermissionRequiredMixin, View):
if individualOptions.show_cables: q['show_cables'] = "on"
if individualOptions.show_logical_connections: q['show_logical_connections'] = "on"
if individualOptions.show_single_cable_logical_conns: q['show_single_cable_logical_conns'] = "on"
if individualOptions.show_neighbors: q['show_neighbors'] = "on"
if individualOptions.show_circuit: q['show_circuit'] = "on"
if individualOptions.show_power: q['show_power'] = "on"
if individualOptions.show_wireless: q['show_wireless'] = "on"
@@ -751,6 +780,7 @@ class TopologyIndividualOptionsView(PermissionRequiredMixin, View):
'show_cables': queryset.show_cables,
'show_logical_connections': queryset.show_logical_connections,
'show_single_cable_logical_conns': queryset.show_single_cable_logical_conns,
'show_neighbors': queryset.show_neighbors,
'show_circuit': queryset.show_circuit,
'show_power': queryset.show_power,
'show_wireless': queryset.show_wireless,