Compare commits

...
4 Commits
Author SHA1 Message Date
mattieserver e68a8a1af0 added tenants (#94) 2022-03-25 10:12:36 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 68e8aa0512 Bump path-parse from 1.0.6 to 1.0.7 (#74)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-18 12:15:05 +01:00
mattieserver b792128415 Fix dark mode (#90)
* fixed dark mode
2022-03-10 11:46:00 +01:00
mattieserver f5d9f589bf Fix circuit error (#87)
* fix 'Interface' object has no attribute 'circuit'
2022-03-09 21:00:55 +01:00
9 changed files with 61 additions and 47 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ class TopologyViewsConfig(PluginConfig):
name = 'netbox_topology_views' name = 'netbox_topology_views'
verbose_name = 'Topology views' verbose_name = 'Topology views'
description = 'An plugin to render topology maps' description = 'An plugin to render topology maps'
version = '1.0.0' version = '1.0.3'
author = 'Mattijs Vanhaverbeke' author = 'Mattijs Vanhaverbeke'
author_email = 'author@example.com' author_email = 'author@example.com'
base_url = 'netbox_topology_views' base_url = 'netbox_topology_views'
@@ -15,7 +15,7 @@ class TopologyViewsConfig(PluginConfig):
'device_img': ['access-switch', 'core-switch', 'firewall', 'router', 'distribution-switch', 'backup', 'storage,wan-network', 'wireless-ap', 'server', 'internal-switch', 'isp-cpe-material', 'non-racked-devices', 'power-units'], 'device_img': ['access-switch', 'core-switch', 'firewall', 'router', 'distribution-switch', 'backup', 'storage,wan-network', 'wireless-ap', 'server', 'internal-switch', 'isp-cpe-material', 'non-racked-devices', 'power-units'],
'allow_coordinates_saving': False, 'allow_coordinates_saving': False,
'preselected_tags' : [], 'preselected_tags' : [],
'enable_circuit_terminations': True, 'enable_circuit_terminations': False,
'draw_default_layout': False 'draw_default_layout': False
} }
+3 -1
View File
@@ -1,10 +1,12 @@
import django_filters import django_filters
from extras.filters import TagFilter from extras.filters import TagFilter
from dcim.models import Device, DeviceRole, Region, Site, Location from dcim.models import Device, DeviceRole, Region, Site, Location
from tenancy.models import TenantGroup, Tenant
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter from utilities.filters import TreeNodeMultipleChoiceFilter
from django.db.models import Q from django.db.models import Q
class DeviceFilterSet(django_filters.FilterSet): class DeviceFilterSet(TenancyFilterSet, django_filters.FilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
+5 -1
View File
@@ -1,18 +1,22 @@
import imp
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from extras.models import Tag from extras.models import Tag
from dcim.models import Device, Site, Region, DeviceRole, Location from dcim.models import Device, Site, Region, DeviceRole, Location
from tenancy.models import TenantGroup, Tenant
from tenancy.forms import TenancyFilterForm
from django.conf import settings from django.conf import settings
from utilities.forms import (TagFilterField, DynamicModelMultipleChoiceField, FilterForm) from utilities.forms import (TagFilterField, DynamicModelMultipleChoiceField, FilterForm)
allow_coordinates_saving = settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"] allow_coordinates_saving = settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"]
class DeviceFilterForm(FilterForm): class DeviceFilterForm(TenancyFilterForm, FilterForm):
model = Device model = Device
field_groups = [ field_groups = [
['q', 'hide_unconnected', 'save_coords'], ['q', 'hide_unconnected', 'save_coords'],
['tenant_group_id', 'tenant_id'],
['region_id', 'site_id', 'location_id'], ['region_id', 'site_id', 'location_id'],
['device_role_id'], ['device_role_id'],
['tag'], ['tag'],
@@ -1 +1 @@
var graph=null,container=null,downloadButton=null,MIME_TYPE="image/png",canvas=null,csrftoken=null,nodes=new vis.DataSet,edges=new vis.DataSet,options={interaction:{hover:!0,hoverConnectedEdges:!0,multiselect:!1},nodes:{shape:"image",brokenImage:"../../static/netbox_topology_views/img/role-unknown.png",size:35,font:{multi:"md",face:"helvetica"}},edges:{length:100,width:2,font:{face:"helvetica"}},physics:{solver:"forceAtlas2Based"}},selected_regions=[],selected_sites=[],coord_save_checkbox=null;function getCookie(e){var t=null;if(document.cookie&&""!==document.cookie)for(var n=document.cookie.split(";"),o=0;o<n.length;o++){var a=n[o].trim();if(a.substring(0,e.length+1)===e+"="){t=decodeURIComponent(a.substring(e.length+1));break}}return t}function htmlTitle(e){return(container=document.createElement("div")).innerHTML=e,container}function addEdge(e){e.title=htmlTitle(e.title),edges.add(e)}function addNode(e){e.title=htmlTitle(e.title),nodes.add(e)}function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){csrftoken=getCookie("csrftoken"),container=document.getElementById("visgraph"),handleLoadData(),downloadButton=document.getElementById("btnDownloadImage"),btnFullView=document.getElementById("btnFullView"),coord_save_checkbox=document.getElementById("id_save_coords")},!1)}function handleLoadData(){null!==topology_data&&(graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),topology_data.edges.forEach(addEdge),topology_data.nodes.forEach(addNode),graph.fit(),canvas=document.getElementById("visgraph").getElementsByTagName("canvas")[0],graph.on("afterDrawing",function(){var e=canvas.toDataURL(MIME_TYPE);downloadButton.href=e,downloadButton.download="topology"}),graph.on("dragEnd",function(e){if(dragged=this.getPositions(e.nodes),coord_save_checkbox.checked&&0!==Object.keys(dragged).length)for(dragged_device in dragged){var t=dragged_device,n=new XMLHttpRequest;n.open("PATCH","/api/plugins/netbox_topology_views/save-coords/save_coords/"),n.setRequestHeader("X-CSRFToken",csrftoken),n.setRequestHeader("Accept","application/json"),n.setRequestHeader("Content-Type","application/json"),n.onreadystatechange=function(){4===n.readyState&&(console.log(n.status),console.log(n.responseText))};var o=JSON.stringify({node_id:t,x:dragged[t].x,y:dragged[t].y});n.send(o)}}))} var graph=null,container=null,downloadButton=null,MIME_TYPE="image/png",canvas=null,csrftoken=null,nodes=new vis.DataSet,edges=new vis.DataSet,options={interaction:{hover:!0,hoverConnectedEdges:!0,multiselect:!1},nodes:{shape:"image",brokenImage:"../../static/netbox_topology_views/img/role-unknown.png",size:35,font:{multi:"md",face:"helvetica"}},edges:{length:100,width:2,font:{face:"helvetica"}},physics:{solver:"forceAtlas2Based"}},selected_regions=[],selected_sites=[],coord_save_checkbox=null,htmlElement=null;function getCookie(e){var t=null;if(document.cookie&&""!==document.cookie)for(var n=document.cookie.split(";"),o=0;o<n.length;o++){var a=n[o].trim();if(a.substring(0,e.length+1)===e+"="){t=decodeURIComponent(a.substring(e.length+1));break}}return t}function htmlTitle(e){return(container=document.createElement("div")).innerHTML=e,container}function addEdge(e){e.title=htmlTitle(e.title),edges.add(e)}function addNode(e){e.title=htmlTitle(e.title),nodes.add(e)}function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){csrftoken=getCookie("csrftoken"),container=document.getElementById("visgraph"),htmlElement=document.getElementsByTagName("html")[0],handleLoadData(),downloadButton=document.getElementById("btnDownloadImage"),btnFullView=document.getElementById("btnFullView"),coord_save_checkbox=document.getElementById("id_save_coords")},!1)}function handleLoadData(){null!==topology_data&&("dark"==htmlElement.dataset.netboxColorMode&&(options.nodes.font.color="#fff"),graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),topology_data.edges.forEach(addEdge),topology_data.nodes.forEach(addNode),graph.fit(),canvas=document.getElementById("visgraph").getElementsByTagName("canvas")[0],graph.on("afterDrawing",function(){var e=canvas.toDataURL(MIME_TYPE);downloadButton.href=e,downloadButton.download="topology"}),graph.on("dragEnd",function(e){if(dragged=this.getPositions(e.nodes),coord_save_checkbox.checked&&0!==Object.keys(dragged).length)for(dragged_device in dragged){var t=dragged_device,n=new XMLHttpRequest;n.open("PATCH","/api/plugins/netbox_topology_views/save-coords/save_coords/"),n.setRequestHeader("X-CSRFToken",csrftoken),n.setRequestHeader("Accept","application/json"),n.setRequestHeader("Content-Type","application/json"),n.onreadystatechange=function(){4===n.readyState&&(console.log(n.status),console.log(n.responseText))};var o=JSON.stringify({node_id:t,x:dragged[t].x,y:dragged[t].y});n.send(o)}}))}
@@ -35,6 +35,7 @@ var options = {
var selected_regions = []; var selected_regions = [];
var selected_sites = []; var selected_sites = [];
var coord_save_checkbox = null; var coord_save_checkbox = null;
var htmlElement = null;
function getCookie(name) { function getCookie(name) {
var cookieValue = null; var cookieValue = null;
@@ -73,6 +74,7 @@ function iniPlotboxIndex() {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
csrftoken = getCookie('csrftoken'); csrftoken = getCookie('csrftoken');
container = document.getElementById('visgraph'); container = document.getElementById('visgraph');
htmlElement = document.getElementsByTagName("html")[0];
handleLoadData(); handleLoadData();
downloadButton = document.getElementById('btnDownloadImage'); downloadButton = document.getElementById('btnDownloadImage');
btnFullView = document.getElementById('btnFullView'); btnFullView = document.getElementById('btnFullView');
@@ -82,6 +84,11 @@ function iniPlotboxIndex() {
function handleLoadData() { function handleLoadData() {
if (topology_data !== null) { if (topology_data !== null) {
if (htmlElement.dataset.netboxColorMode == "dark") {
options.nodes.font.color = "#fff";
}
graph = null; graph = null;
nodes = new vis.DataSet(); nodes = new vis.DataSet();
edges = new vis.DataSet(); edges = new vis.DataSet();
+40 -39
View File
@@ -66,52 +66,53 @@ def get_topology_data(queryset, hide_unconnected):
device_has_connections = True device_has_connections = True
else: else:
if settings.PLUGINS_CONFIG["netbox_topology_views"]["enable_circuit_terminations"]: if settings.PLUGINS_CONFIG["netbox_topology_views"]["enable_circuit_terminations"]:
if link_from.termination_a.circuit.id not in circuit_ids: if link_from.termination_a_type.name == "circuit termination":
circuit_ids.append(link_from.termination_a.circuit.id) if link_from.termination_a.circuit.id not in circuit_ids:
edge_ids += 1 circuit_ids.append(link_from.termination_a.circuit.id)
edge_ids += 1
cable_b_dev_name = link_from.termination_b.device.name cable_b_dev_name = link_from.termination_b.device.name
if cable_b_dev_name is None: if cable_b_dev_name is None:
cable_b_dev_name = "device B name unknown" cable_b_dev_name = "device B name unknown"
cable_b_name = link_from.termination_b.name cable_b_name = link_from.termination_b.name
if cable_b_name is None: if cable_b_name is None:
cable_b_name = "cable B name unknown" cable_b_name = "cable B name unknown"
edge = {} edge = {}
edge["id"] = edge_ids edge["id"] = edge_ids
edge["to"] = link_from.termination_b.device.id edge["to"] = link_from.termination_b.device.id
edge["dashes"] = True edge["dashes"] = True
title = "" title = ""
title += "Circuit provider: " + link_from.termination_a.circuit.provider.name + "<br>" title += "Circuit provider: " + link_from.termination_a.circuit.provider.name + "<br>"
title += "Termination between <br>" title += "Termination between <br>"
title += cable_b_dev_name + " [" + cable_b_name + "]<br>" title += cable_b_dev_name + " [" + cable_b_name + "]<br>"
if link_from.termination_a.circuit.termination_a is not None and link_from.termination_a.circuit.termination_a.cable is not None and link_from.termination_a.circuit.termination_a.cable.id != link_from.id and link_from.termination_a.circuit.termination_a.cable.termination_b is not None and link_from.termination_a.circuit.termination_a.cable.termination_b.device is not None: if link_from.termination_a.circuit.termination_a is not None and link_from.termination_a.circuit.termination_a.cable is not None and link_from.termination_a.circuit.termination_a.cable.id != link_from.id and link_from.termination_a.circuit.termination_a.cable.termination_b is not None and link_from.termination_a.circuit.termination_a.cable.termination_b.device is not None:
edge["from"] = link_from.termination_a.circuit.termination_a.cable.termination_b.device.id edge["from"] = link_from.termination_a.circuit.termination_a.cable.termination_b.device.id
cable_a_dev_name = link_from.termination_a.circuit.termination_a.cable.termination_b.device.name cable_a_dev_name = link_from.termination_a.circuit.termination_a.cable.termination_b.device.name
if cable_a_dev_name is None: if cable_a_dev_name is None:
cable_a_dev_name = "device B name unknown" cable_a_dev_name = "device B name unknown"
cable_b_name = link_from.termination_a.circuit.termination_a.cable.termination_b.name cable_b_name = link_from.termination_a.circuit.termination_a.cable.termination_b.name
if cable_a_name is None: if cable_a_name is None:
cable_a_name = "cable B name unknown" cable_a_name = "cable B name unknown"
title += cable_a_dev_name + " [" + cable_a_name + "]<br>" title += cable_a_dev_name + " [" + cable_a_name + "]<br>"
edge["title"] = title edge["title"] = title
edges.append(edge) edges.append(edge)
if link_from.termination_a.circuit.termination_z is not None and link_from.termination_a.circuit.termination_z.cable is not None and link_from.termination_a.circuit.termination_z.cable.id != link_from.id and link_from.termination_a.circuit.termination_z.cable.termination_b is not None and link_from.termination_a.circuit.termination_z.cable.termination_b.device is not None: if link_from.termination_a.circuit.termination_z is not None and link_from.termination_a.circuit.termination_z.cable is not None and link_from.termination_a.circuit.termination_z.cable.id != link_from.id and link_from.termination_a.circuit.termination_z.cable.termination_b is not None and link_from.termination_a.circuit.termination_z.cable.termination_b.device is not None:
edge["from"] = link_from.termination_a.circuit.termination_z.cable.termination_b.device.id edge["from"] = link_from.termination_a.circuit.termination_z.cable.termination_b.device.id
cable_a_dev_name = link_from.termination_a.circuit.termination_z.cable.termination_b.device.name cable_a_dev_name = link_from.termination_a.circuit.termination_z.cable.termination_b.device.name
if cable_a_dev_name is None: if cable_a_dev_name is None:
cable_a_dev_name = "device B name unknown" cable_a_dev_name = "device B name unknown"
cable_a_name = link_from.termination_a.circuit.termination_z.cable.termination_b.name cable_a_name = link_from.termination_a.circuit.termination_z.cable.termination_b.name
if cable_a_name is None: if cable_a_name is None:
cable_a_name = "cable B name unknown" cable_a_name = "cable B name unknown"
title += cable_a_dev_name + " [" + cable_a_name + "]<br>" title += cable_a_dev_name + " [" + cable_a_name + "]<br>"
edge["title"] = title edge["title"] = title
edges.append(edge) edges.append(edge)
if qs_device.id not in nodes_ids: if qs_device.id not in nodes_ids:
if hide_unconnected == None or (hide_unconnected is True and device_has_connections is True): if hide_unconnected == None or (hide_unconnected is True and device_has_connections is True):
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "netbox_topology_views", "name": "netbox_topology_views",
"version": "1.0.0", "version": "1.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"name": "netbox_topology_views", "name": "netbox_topology_views",
"version": "1.0.0", "version": "1.0.3",
"scripts": { "scripts": {
"resources": "gulp build", "resources": "gulp build",
"resources_dev": "gulp build_dev" "resources_dev": "gulp build_dev"
+1 -1
View File
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
setup( setup(
name='netbox-topology-views', name='netbox-topology-views',
version='1.0.0', version='1.0.3',
description='An NetBox plugin to create Topology maps', description='An NetBox plugin to create Topology maps',
url='https://github.com/mattieserver/netbox-topology-views', url='https://github.com/mattieserver/netbox-topology-views',
author='Mattijs Vanhaverbeke', author='Mattijs Vanhaverbeke',