Closes #252,#78,#177,#265: Move options from config file to GUI (#262)
* Added some individual options * Added general options * Added show_single_cable_logical_conns and draw_default_layout * Added ignore_cable_type to IndividualOptions * Corrected permission, tiny improvements * Add preselected_device_roles to IndividualOptions * Add preselected_tags * Updated documentation * Update README.md * Corrected queryset for preselected_tags * Update README.md * move supported_termination_types to inside the function to prevent migration issues * removed general options * added new migration script --------- Co-authored-by: Mattijs Vanhaverbeke <mattijs.vanhaverbeke@ebo-enterprises.com>
This commit is contained in:
co-authored by
Mattijs Vanhaverbeke
parent
4fbc2fd8ce
commit
5d20a7ad15
@@ -11,25 +11,10 @@ class TopologyViewsConfig(PluginConfig):
|
||||
base_url = "netbox_topology_views"
|
||||
required_settings = []
|
||||
default_settings = {
|
||||
"preselected_device_roles": [
|
||||
"Firewall",
|
||||
"Router",
|
||||
"Distribution Switch",
|
||||
"Core Switch",
|
||||
"Internal Switch",
|
||||
"Access Switch",
|
||||
"Server",
|
||||
"Storage",
|
||||
"Backup",
|
||||
"Wireless AP",
|
||||
],
|
||||
"ignore_cable_type": [],
|
||||
"static_image_directory": "netbox_topology_views/img",
|
||||
"allow_coordinates_saving": False,
|
||||
"always_save_coordinates": False,
|
||||
"preselected_tags": [],
|
||||
"draw_default_layout": False,
|
||||
"hide_single_cable_logical_conns": False,
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from dcim.models import Device, DeviceRole
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from netbox.api.serializers import NetBoxModelSerializer
|
||||
|
||||
from netbox_topology_views.models import RoleImage
|
||||
from netbox_topology_views.models import RoleImage, IndividualOptions
|
||||
|
||||
|
||||
class TopologyDummySerializer(ModelSerializer):
|
||||
@@ -20,3 +21,8 @@ class DeviceRoleSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = DeviceRole
|
||||
fields = ("name", "slug", "color", "vm_role", "description")
|
||||
|
||||
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")
|
||||
+134
-15
@@ -12,17 +12,14 @@ from dcim.choices import DeviceStatusChoices
|
||||
from tenancy.models import TenantGroup, Tenant
|
||||
from tenancy.forms import TenancyFilterForm
|
||||
from django.conf import settings
|
||||
from netbox.forms import NetBoxModelFilterSetForm
|
||||
from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm
|
||||
from utilities.forms import (
|
||||
TagFilterField,
|
||||
DynamicModelMultipleChoiceField,
|
||||
MultipleChoiceField,
|
||||
widgets,
|
||||
)
|
||||
|
||||
allow_coordinates_saving = bool(
|
||||
settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"]
|
||||
)
|
||||
|
||||
from .models import IndividualOptions
|
||||
|
||||
class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||
model = Device
|
||||
@@ -32,11 +29,12 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||
(
|
||||
"q",
|
||||
"filter_id",
|
||||
"hide_unconnected",
|
||||
"save_coords",
|
||||
"show_unconnected",
|
||||
"show_cables",
|
||||
"show_circuit",
|
||||
"show_logical_connections",
|
||||
"show_single_cable_logical_conns",
|
||||
"show_power",
|
||||
"show_wireless",
|
||||
),
|
||||
@@ -104,12 +102,27 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||
},
|
||||
label=_("Rack"),
|
||||
)
|
||||
hide_unconnected = forms.BooleanField(
|
||||
label=_("Hide Unconnected"), required=False, initial=False
|
||||
status = MultipleChoiceField(
|
||||
choices=DeviceStatusChoices, required=False, label=_("Device Status")
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
# options
|
||||
save_coords = forms.BooleanField(
|
||||
label=_("Save Coordinates"),
|
||||
required=False,
|
||||
disabled=(not settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"] or settings.PLUGINS_CONFIG["netbox_topology_views"]["always_save_coordinates"]),
|
||||
initial=(settings.PLUGINS_CONFIG["netbox_topology_views"]["always_save_coordinates"])
|
||||
)
|
||||
show_unconnected = forms.BooleanField(
|
||||
label=_("Show Unconnected"), 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
|
||||
)
|
||||
@@ -122,12 +135,118 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||
show_power = forms.BooleanField(
|
||||
label=_("Show Power Feeds"), required=False, initial=False
|
||||
)
|
||||
save_coords = forms.BooleanField(
|
||||
label=_("Save Coordinates"),
|
||||
|
||||
class IndividualOptionsForm(NetBoxModelForm):
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
(
|
||||
"user_id",
|
||||
"ignore_cable_type",
|
||||
"preselected_device_roles",
|
||||
"preselected_tags",
|
||||
"show_unconnected",
|
||||
"show_cables",
|
||||
"show_circuit",
|
||||
"show_logical_connections",
|
||||
"show_single_cable_logical_conns",
|
||||
"show_power",
|
||||
"show_wireless",
|
||||
"draw_default_layout",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
user_id = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
ignore_cable_type = MultipleChoiceField(
|
||||
label=_("Ignore Termination Types"),
|
||||
required=False,
|
||||
choices=IndividualOptions.CHOICES,
|
||||
help_text=_("Choose Termination Types that you want to be ignored. "
|
||||
"If any ignored Termination Type is part of a connection, the "
|
||||
"cable is not displayed.")
|
||||
)
|
||||
preselected_device_roles = DynamicModelMultipleChoiceField(
|
||||
label=_("Preselected Device Role"),
|
||||
queryset=DeviceRole.objects.all(),
|
||||
required=False,
|
||||
disabled=(not allow_coordinates_saving),
|
||||
help_text=_("Select Device Roles that you want to have "
|
||||
"preselected in the filter tab.")
|
||||
)
|
||||
status = MultipleChoiceField(
|
||||
choices=DeviceStatusChoices, required=False, label=_("Device Status")
|
||||
preselected_tags = forms.ModelMultipleChoiceField(
|
||||
label=_("Preselected Tags"),
|
||||
queryset=Device.tags.all(),
|
||||
required=False,
|
||||
widget=widgets.StaticSelectMultiple,
|
||||
help_text=_("Select Tags that you want to have "
|
||||
"preselected in the filter tab.")
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
show_unconnected = forms.BooleanField(
|
||||
label=_("Show Unconnected"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Draws 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'.")
|
||||
)
|
||||
show_cables = forms.BooleanField(
|
||||
label =_("Show Cables"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Displays connections between interfaces that are connected "
|
||||
"with one or more cables. These connections are displayed as solid "
|
||||
"lines in the color of the cable.")
|
||||
)
|
||||
show_logical_connections = forms.BooleanField(
|
||||
label =_("Show Logical Connections"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Displays connections between devices that are not "
|
||||
"directly connected (e.g. via patch panels). These connections "
|
||||
"are displayed as yellow dotted lines.")
|
||||
)
|
||||
show_single_cable_logical_conns = forms.BooleanField(
|
||||
label = ("Show redundant Cable and Locigal Connection"),
|
||||
required = False,
|
||||
initial=False,
|
||||
help_text=_("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.")
|
||||
)
|
||||
show_circuit = forms.BooleanField(
|
||||
label=_("Show Circuit Terminations"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Displays connections between circuit terminations. "
|
||||
"These connections are displayed as blue dashed lines.")
|
||||
)
|
||||
show_power = forms.BooleanField(
|
||||
label=_("Show Power Feeds"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("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'.")
|
||||
)
|
||||
show_wireless = forms.BooleanField(
|
||||
label =_("Show Wireless Links"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Displays wireless connections. These connections are "
|
||||
"displayed as blue dotted lines.")
|
||||
)
|
||||
draw_default_layout = forms.BooleanField(
|
||||
label = ("Draw Default Layout"),
|
||||
required=False,
|
||||
initial=False,
|
||||
help_text=_("Enable this option if you want to draw the topology on "
|
||||
"the initial load (when you go to the topology plugin page).")
|
||||
)
|
||||
|
||||
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'
|
||||
]
|
||||
@@ -0,0 +1,42 @@
|
||||
# Generated by Django 4.1.4 on 2023-03-19 14:13
|
||||
|
||||
from django.db import migrations, models
|
||||
import taggit.managers
|
||||
import utilities.json
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0167_module_status'),
|
||||
('extras', '0084_staging'),
|
||||
('netbox_topology_views', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IndividualOptions',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||
('user_id', models.IntegerField(null=True, unique=True)),
|
||||
('ignore_cable_type', models.CharField(blank=True, max_length=255)),
|
||||
('show_unconnected', models.BooleanField(default=False)),
|
||||
('show_cables', models.BooleanField(default=False)),
|
||||
('show_logical_connections', models.BooleanField(default=False)),
|
||||
('show_single_cable_logical_conns', models.BooleanField(default=False)),
|
||||
('show_circuit', models.BooleanField(default=False)),
|
||||
('show_power', models.BooleanField(default=False)),
|
||||
('show_wireless', models.BooleanField(default=False)),
|
||||
('draw_default_layout', models.BooleanField(default=False)),
|
||||
('preselected_device_roles', models.ManyToManyField(blank=True, db_table='netbox_topology_views_individualoptions_preselected_device', related_name='+', to='dcim.devicerole')),
|
||||
('preselected_tags', models.ManyToManyField(blank=True, db_table='netbox_topology_views_individualoptions_preselected_tag', related_name='+', to='extras.tag')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -2,10 +2,12 @@ from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from dcim.models import DeviceRole
|
||||
from extras.models import Tag
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.templatetags.static import static
|
||||
from netbox.models import NetBoxModel
|
||||
from netbox.models.features import (
|
||||
ChangeLoggingMixin,
|
||||
ExportTemplatesMixin,
|
||||
@@ -91,3 +93,62 @@ class RoleImage(ChangeLoggingMixin, ExportTemplatesMixin, WebhooksMixin):
|
||||
except ValueError:
|
||||
return self.get_default_image(dir)
|
||||
return static(f"/{self.image}")
|
||||
|
||||
class IndividualOptions(NetBoxModel):
|
||||
CHOICES = (
|
||||
('interface', 'interface'),
|
||||
('front port', 'front port'),
|
||||
('rear port', 'rear port'),
|
||||
('power outlet', 'power outlet'),
|
||||
('power port', 'power port'),
|
||||
('console port', 'console port'),
|
||||
('console server port', 'console server port'),
|
||||
)
|
||||
|
||||
user_id = models.IntegerField(
|
||||
null=True,
|
||||
unique=True
|
||||
)
|
||||
ignore_cable_type = models.CharField(
|
||||
max_length = 255,
|
||||
blank = True,
|
||||
)
|
||||
preselected_device_roles = models.ManyToManyField(
|
||||
to='dcim.DeviceRole',
|
||||
related_name='+',
|
||||
blank=True,
|
||||
db_table='netbox_topology_views_individualoptions_preselected_device',
|
||||
)
|
||||
preselected_tags = models.ManyToManyField(
|
||||
to='extras.Tag',
|
||||
related_name='+',
|
||||
blank=True,
|
||||
db_table='netbox_topology_views_individualoptions_preselected_tag',
|
||||
)
|
||||
show_unconnected = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_cables = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_logical_connections = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_single_cable_logical_conns = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_circuit = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_power = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
show_wireless = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
draw_default_layout = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
|
||||
def __str___(self):
|
||||
return f"{self.user_id}"
|
||||
@@ -4,7 +4,12 @@ menu = PluginMenu(
|
||||
label='Topology Views',
|
||||
icon_class="mdi mdi-sitemap",
|
||||
groups=(
|
||||
('Topology', (PluginMenuItem(link="plugins:netbox_topology_views:home", link_text="Topology"),),),
|
||||
('CUSTOMIZATION', (PluginMenuItem(link="plugins:netbox_topology_views:images", link_text="Topology Images"),),),
|
||||
('TOPOLOGY', (PluginMenuItem(link="plugins:netbox_topology_views:home", link_text="Topology"),),),
|
||||
('PREFERENCES',
|
||||
(
|
||||
PluginMenuItem(link="plugins:netbox_topology_views:images", link_text="Images"),
|
||||
PluginMenuItem(link="plugins:netbox_topology_views:individualoptions", link_text="Individual Options"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{% extends 'generic/object_edit.html' %}
|
||||
|
||||
{% block title %}Topology Views Individual Options{% endblock %}
|
||||
|
||||
{% block tabs %} {% endblock tabs %}
|
||||
@@ -9,4 +9,5 @@ urlpatterns = (
|
||||
path("", RedirectView.as_view(url="topology/", permanent=True)),
|
||||
path("topology/", views.TopologyHomeView.as_view(), name="home"),
|
||||
path("images/", views.TopologyImagesView.as_view(), name="images"),
|
||||
path("individualoptions/", views.TopologyIndividualOptionsView.as_view(), name="individualoptions"),
|
||||
)
|
||||
|
||||
+110
-70
@@ -18,9 +18,11 @@ from dcim.models import (
|
||||
RearPort,
|
||||
)
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Q, QuerySet
|
||||
from django.db.models.functions import Lower
|
||||
from django.http import HttpRequest, HttpResponseRedirect, QueryDict
|
||||
from django.shortcuts import render
|
||||
from django.views.generic import View
|
||||
@@ -28,8 +30,8 @@ from extras.models import Tag
|
||||
from wireless.models import WirelessLink
|
||||
|
||||
from netbox_topology_views.filters import DeviceFilterSet
|
||||
from netbox_topology_views.forms import DeviceFilterForm
|
||||
from netbox_topology_views.models import RoleImage
|
||||
from netbox_topology_views.forms import DeviceFilterForm, IndividualOptionsForm
|
||||
from netbox_topology_views.models import RoleImage, IndividualOptions
|
||||
from netbox_topology_views.utils import (
|
||||
CONF_IMAGE_DIR,
|
||||
find_image_url,
|
||||
@@ -38,15 +40,6 @@ from netbox_topology_views.utils import (
|
||||
image_static_url,
|
||||
)
|
||||
|
||||
supported_termination_types = [
|
||||
"interface",
|
||||
"front port",
|
||||
"rear port",
|
||||
"power outlet",
|
||||
"power port",
|
||||
"console port",
|
||||
"console server port",
|
||||
]
|
||||
|
||||
|
||||
def get_image_for_entity(entity: Union[Device, Circuit, PowerPanel, PowerFeed]):
|
||||
@@ -261,14 +254,21 @@ def create_circuit_termination(termination):
|
||||
|
||||
def get_topology_data(
|
||||
queryset: QuerySet,
|
||||
hide_unconnected: bool,
|
||||
individualOptions: IndividualOptions,
|
||||
show_unconnected: bool,
|
||||
save_coords: bool,
|
||||
show_cables: bool,
|
||||
show_circuit: bool,
|
||||
show_logical_connections: bool,
|
||||
show_single_cable_logical_conns: bool,
|
||||
show_power: bool,
|
||||
show_wireless: bool,
|
||||
):
|
||||
|
||||
supported_termination_types = []
|
||||
for t in IndividualOptions.CHOICES:
|
||||
supported_termination_types.append(t[1])
|
||||
|
||||
if not queryset:
|
||||
return None
|
||||
|
||||
@@ -282,14 +282,8 @@ def get_topology_data(
|
||||
nodes_provider_networks = {}
|
||||
cable_ids = DefaultDict(dict)
|
||||
interface_ids = DefaultDict(dict)
|
||||
ignore_cable_type = settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"ignore_cable_type"
|
||||
]
|
||||
hide_single_cable_logical_conns = bool(
|
||||
settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"hide_single_cable_logical_conns"
|
||||
]
|
||||
)
|
||||
|
||||
ignore_cable_type = individualOptions.ignore_cable_type
|
||||
|
||||
device_ids = [d.pk for d in queryset]
|
||||
site_ids = [d.site_id for d in queryset]
|
||||
@@ -301,7 +295,7 @@ def get_topology_data(
|
||||
for circuit_termination in circuit_terminations:
|
||||
circuit_termination: CircuitTermination
|
||||
if (
|
||||
not hide_unconnected
|
||||
show_unconnected
|
||||
and circuit_termination.circuit_id not in nodes_circuits
|
||||
):
|
||||
nodes_circuits[
|
||||
@@ -358,7 +352,7 @@ def get_topology_data(
|
||||
if termination.device_id in device_ids:
|
||||
circuit_has_connections = True
|
||||
|
||||
if circuit_has_connections and hide_unconnected:
|
||||
if circuit_has_connections and not show_unconnected:
|
||||
if circuit_termination.circuit_id not in nodes_circuits:
|
||||
nodes_circuits[
|
||||
circuit_termination.circuit.pk
|
||||
@@ -376,15 +370,15 @@ def get_topology_data(
|
||||
)
|
||||
|
||||
for power_feed in power_feeds:
|
||||
if not hide_unconnected or (
|
||||
hide_unconnected and power_feed.cable_id is not None
|
||||
if show_unconnected or (
|
||||
not show_unconnected and power_feed.cable_id is not None
|
||||
):
|
||||
if power_feed.power_panel_id not in nodes_powerpanel:
|
||||
nodes_powerpanel[power_feed.power_panel.pk] = power_feed.power_panel
|
||||
|
||||
power_link_name = ""
|
||||
if power_feed.pk not in nodes_powerfeed:
|
||||
if hide_unconnected:
|
||||
if not show_unconnected:
|
||||
if power_feed.link_peers[0].device_id in device_ids:
|
||||
nodes_powerfeed[power_feed.pk] = power_feed
|
||||
power_link_name = power_feed.link_peers[0].name
|
||||
@@ -438,7 +432,7 @@ def get_topology_data(
|
||||
# print('Destination interface already exists, ignoring')
|
||||
continue
|
||||
|
||||
if hide_single_cable_logical_conns and interface.cable_id==destination.cable_id and show_cables:
|
||||
if not show_single_cable_logical_conns and interface.cable_id==destination.cable_id and show_cables:
|
||||
# interface connection is the same as the cable connection, ignore this connection
|
||||
continue
|
||||
|
||||
@@ -569,7 +563,7 @@ def get_topology_data(
|
||||
)
|
||||
|
||||
for qs_device in queryset:
|
||||
if qs_device.pk not in nodes_devices and not hide_unconnected:
|
||||
if qs_device.pk not in nodes_devices and show_unconnected:
|
||||
nodes_devices[qs_device.pk] = qs_device
|
||||
|
||||
results = {}
|
||||
@@ -598,16 +592,27 @@ class TopologyHomeView(PermissionRequiredMixin, View):
|
||||
self.model = self.queryset.model
|
||||
topo_data = None
|
||||
|
||||
individualOptions, created = IndividualOptions.objects.get_or_create(
|
||||
user_id=request.user.id,
|
||||
)
|
||||
|
||||
if request.GET:
|
||||
save_coords = False
|
||||
if "save_coords" in request.GET:
|
||||
if request.GET["save_coords"] == "on":
|
||||
save_coords = True
|
||||
# General options overrides
|
||||
if save_coords == True and settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"] == False:
|
||||
save_coords = False
|
||||
messages.warning(request, "Coordinate saving not allowed. Setting has been overridden")
|
||||
elif settings.PLUGINS_CONFIG["netbox_topology_views"]["always_save_coordinates"] == True:
|
||||
save_coords = True
|
||||
|
||||
hide_unconnected = False
|
||||
if "hide_unconnected" in request.GET:
|
||||
if request.GET["hide_unconnected"] == "on":
|
||||
hide_unconnected = True
|
||||
# Individual options
|
||||
show_unconnected = False
|
||||
if "show_unconnected" in request.GET:
|
||||
if request.GET["show_unconnected"] == "on":
|
||||
show_unconnected = True
|
||||
|
||||
show_power = False
|
||||
if "show_power" in request.GET:
|
||||
@@ -624,6 +629,11 @@ class TopologyHomeView(PermissionRequiredMixin, View):
|
||||
if request.GET["show_logical_connections"] == "on" :
|
||||
show_logical_connections = True
|
||||
|
||||
show_single_cable_logical_conns = False
|
||||
if "show_single_cable_logical_conns" in request.GET:
|
||||
if request.GET["show_single_cable_logical_conns"] == "on" :
|
||||
show_single_cable_logical_conns = True
|
||||
|
||||
show_cables = False
|
||||
if "show_cables" in request.GET:
|
||||
if request.GET["show_cables"] == "on" :
|
||||
@@ -634,60 +644,45 @@ class TopologyHomeView(PermissionRequiredMixin, View):
|
||||
if request.GET["show_wireless"] == "on" :
|
||||
show_wireless = True
|
||||
|
||||
if "draw_init" in request.GET:
|
||||
if request.GET["draw_init"].lower() == "true":
|
||||
topo_data = get_topology_data(
|
||||
self.queryset,
|
||||
hide_unconnected,
|
||||
save_coords,
|
||||
show_cables,
|
||||
show_circuit,
|
||||
show_logical_connections,
|
||||
show_power,
|
||||
show_wireless,
|
||||
)
|
||||
else:
|
||||
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,
|
||||
hide_unconnected,
|
||||
individualOptions,
|
||||
show_unconnected,
|
||||
save_coords,
|
||||
show_cables,
|
||||
show_circuit,
|
||||
show_logical_connections,
|
||||
show_single_cable_logical_conns,
|
||||
show_power,
|
||||
show_wireless,
|
||||
)
|
||||
|
||||
else:
|
||||
preselected_device_roles = settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"preselected_device_roles"
|
||||
]
|
||||
preselected_tags = settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"preselected_tags"
|
||||
]
|
||||
always_save_coordinates = bool(
|
||||
settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"always_save_coordinates"
|
||||
]
|
||||
)
|
||||
|
||||
q_device_role_id = DeviceRole.objects.filter(
|
||||
name__in=preselected_device_roles
|
||||
).values_list("id", flat=True)
|
||||
q_tags = Tag.objects.filter(name__in=preselected_tags).values_list(
|
||||
"name", flat=True
|
||||
)
|
||||
# No GET-Request in URL. We most likely came here from the navigation menu.
|
||||
preselected_device_roles = IndividualOptions.objects.get(id=individualOptions.id).preselected_device_roles.all().values_list('id', flat=True)
|
||||
preselected_tags = IndividualOptions.objects.get(id=individualOptions.id).preselected_tags.all().values_list(Lower('name'), flat=True)
|
||||
|
||||
q = QueryDict(mutable=True)
|
||||
q.setlist("device_role_id", list(q_device_role_id))
|
||||
q.setlist("tag", list(q_tags))
|
||||
q["draw_init"] = settings.PLUGINS_CONFIG["netbox_topology_views"][
|
||||
"draw_default_layout"
|
||||
]
|
||||
if always_save_coordinates:
|
||||
q["save_coords"] = "on"
|
||||
q.setlist("device_role_id", list(preselected_device_roles))
|
||||
q.setlist("tag", list(preselected_tags))
|
||||
|
||||
if individualOptions.show_unconnected: q['show_unconnected'] = "on"
|
||||
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_circuit: q['show_circuit'] = "on"
|
||||
if individualOptions.show_power: q['show_power'] = "on"
|
||||
if individualOptions.show_wireless: q['show_wireless'] = "on"
|
||||
if individualOptions.draw_default_layout:
|
||||
q['draw_init'] = "true"
|
||||
else:
|
||||
q['draw_init'] = "false"
|
||||
|
||||
query_string = q.urlencode()
|
||||
return HttpResponseRedirect(f"{request.path}?{query_string}")
|
||||
|
||||
|
||||
if is_htmx(request):
|
||||
return render(
|
||||
request,
|
||||
@@ -768,3 +763,48 @@ class TopologyImagesView(PermissionRequiredMixin, View):
|
||||
"images": images,
|
||||
},
|
||||
)
|
||||
|
||||
class TopologyIndividualOptionsView(PermissionRequiredMixin, View):
|
||||
permission_required = 'netbox_topology_views.change_individualoptions'
|
||||
|
||||
def post(self, request):
|
||||
instance = IndividualOptions.objects.get(user_id=request.user.id)
|
||||
form = IndividualOptionsForm(request.POST, instance=instance)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, "Options have been sucessfully saved")
|
||||
else:
|
||||
messages.error(request, form.errors)
|
||||
|
||||
return HttpResponseRedirect("./")
|
||||
|
||||
def get(self, request):
|
||||
queryset, created = IndividualOptions.objects.get_or_create(
|
||||
user_id=request.user.id,
|
||||
)
|
||||
|
||||
form = IndividualOptionsForm(
|
||||
initial={
|
||||
'user_id': request.user.id,
|
||||
'ignore_cable_type': tuple(queryset.ignore_cable_type.translate({ord(i): None for i in '[]\''}).split(', ')),
|
||||
'preselected_device_roles': IndividualOptions.objects.get(id=queryset.id).preselected_device_roles.all(),
|
||||
'preselected_tags': IndividualOptions.objects.get(id=queryset.id).preselected_tags.all(),
|
||||
'show_unconnected': queryset.show_unconnected,
|
||||
'show_cables': queryset.show_cables,
|
||||
'show_logical_connections': queryset.show_logical_connections,
|
||||
'show_single_cable_logical_conns': queryset.show_single_cable_logical_conns,
|
||||
'show_circuit': queryset.show_circuit,
|
||||
'show_power': queryset.show_power,
|
||||
'show_wireless': queryset.show_wireless,
|
||||
'draw_default_layout': queryset.draw_default_layout,
|
||||
},
|
||||
)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"netbox_topology_views/individual_options.html",
|
||||
{
|
||||
"form": form,
|
||||
"object": queryset,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user