added download button, fixed perms
This commit is contained in:
@@ -63,3 +63,12 @@ Run `pip install netbox-topology-views --upgrade` in your venv.
|
|||||||
Run `python3 manage.py collectstatic --no-input`
|
Run `python3 manage.py collectstatic --no-input`
|
||||||
|
|
||||||
Clear you browser cache.
|
Clear you browser cache.
|
||||||
|
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
|
||||||
|
To view `/plugins/topology-views/` you need the following permissions:
|
||||||
|
+ dcim | device | can view device
|
||||||
|
+ dcim | site | can view site
|
||||||
|
+ extras | tag | can view tag
|
||||||
|
+ dcim | device role | can view device role
|
||||||
@@ -30,7 +30,7 @@ class PreSelectTagsViewSet(ReadOnlyModelViewSet):
|
|||||||
queryset = Tag.objects.filter(name__in=preselected_tags)
|
queryset = Tag.objects.filter(name__in=preselected_tags)
|
||||||
serializer_class = PreTagSerializer
|
serializer_class = PreTagSerializer
|
||||||
|
|
||||||
class SaveCoordsViewSet(GenericViewSet):
|
class SaveCoordsViewSet(ReadOnlyModelViewSet):
|
||||||
queryset = Device.objects.all()
|
queryset = Device.objects.all()
|
||||||
serializer_class = TopologyDummySerializer
|
serializer_class = TopologyDummySerializer
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class SaveCoordsViewSet(GenericViewSet):
|
|||||||
results["status"] = "not allowed to save coords"
|
results["status"] = "not allowed to save coords"
|
||||||
return Response(results, status=500)
|
return Response(results, status=500)
|
||||||
|
|
||||||
class SearchViewSet(GenericViewSet):
|
class SearchViewSet(ReadOnlyModelViewSet):
|
||||||
#_ignore_model_permissions = True
|
#_ignore_model_permissions = True
|
||||||
#permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
#permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
||||||
|
|
||||||
@@ -96,24 +96,23 @@ class SearchViewSet(GenericViewSet):
|
|||||||
return filter_devices
|
return filter_devices
|
||||||
|
|
||||||
|
|
||||||
@action(detail=False, methods=['post'])
|
@action(detail=False, methods=['get'])
|
||||||
def search(self, request):
|
def search(self, request):
|
||||||
name = None
|
name = request.query_params.get('name', None)
|
||||||
sites = None
|
if name == "":
|
||||||
devicerole = None
|
name = None
|
||||||
tags = None
|
|
||||||
if "devicerole" in request.data:
|
sites = request.query_params.getlist('sites[]', None)
|
||||||
if request.data["devicerole"]:
|
if sites == []:
|
||||||
devicerole = request.data["devicerole"]
|
sites = None
|
||||||
if "sites" in request.data:
|
|
||||||
if request.data["sites"]:
|
devicerole = request.query_params.getlist('devicerole[]', None)
|
||||||
sites = request.data["sites"]
|
if devicerole == []:
|
||||||
if "name" in request.data:
|
devicerole = None
|
||||||
if request.data["name"]:
|
|
||||||
name = request.data["name"]
|
tags = request.query_params.getlist('tags[]', None)
|
||||||
if "tags" in request.data:
|
if tags == []:
|
||||||
if request.data["tags"]:
|
tags = None
|
||||||
tags = request.data["tags"]
|
|
||||||
|
|
||||||
devices = self._filter(sites, devicerole, name, tags)
|
devices = self._filter(sites, devicerole, name, tags)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
var graph=null,container=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"}};function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){container=document.getElementById("visgraph"),csrftoken=jQuery("[name=csrfmiddlewaretoken]").val(),startLoadSearchBar(),handleButtonPress()},!1)}function startLoadSearchBar(){$("#device-roles").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/device-roles/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#sites").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/sites/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#tags").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/extras/tags/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}});var s=$("#device-roles");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselectdeviceroles/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);s.append(a).trigger("change"),s.trigger({type:"select2:select",params:{data:t}})})});var n=$("#tags");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselecttags/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);n.append(a).trigger("change"),n.trigger({type:"select2:select",params:{data:t}})})})}function handleButtonPress(){$("#search-form").submit(function(e){$("#status").html('<span class="label label-info">Loading data</span>'),e.preventDefault();var t=$("#name").val(),a=$("#device-roles").val(),s=$("#sites").val(),n=$("#tags").val();$.ajax({type:"POST",url:"../../api/plugins/topology-views/search/search/",data:JSON.stringify({name:t,devicerole:a,sites:s,tags:n}),headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",dataType:"json",success:function(e){$("#status").html('<span class="label label-info">Drawing network</span>'),graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),$.each(e.nodes,function(e,t){nodes.add(t)}),$.each(e.edges,function(e,t){edges.add(t)}),graph.fit(),graph.on("afterDrawing",function(){$("#status").html('<span class="label label-success">Ready</span>')}),graph.on("dragEnd",function(e){dragged=this.getPositions(e.nodes),$.each(dragged,function(e,t){$("#coordstatus").html(""),$("#checkSaveCoordinates").is(":checked")&&$.ajax({url:"../../api/plugins/topology-views/save-coords/save_coords/",type:"POST",dataType:"json",headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",data:JSON.stringify({node_id:e,x:t.x,y:t.y}),error:function(e){$("#coordstatus").html('<span class="label label-warning">Failed to update coordinates</span>')},success:function(e){$("#coordstatus").html('<span class="label label-success">Updated coordinates</span>')}})})})},error:function(e){$("#status").html('<span class="label label-warning">Something went wrong</span>')}})})}
|
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"}};function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){container=document.getElementById("visgraph"),csrftoken=jQuery("[name=csrfmiddlewaretoken]").val(),startLoadSearchBar(),handleButtonPress(),downloadButton=document.getElementById("btnDownloadImage")},!1)}function startLoadSearchBar(){$("#device-roles").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/device-roles/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#sites").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/sites/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#tags").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/extras/tags/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}});var n=$("#device-roles");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselectdeviceroles/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);n.append(a).trigger("change"),n.trigger({type:"select2:select",params:{data:t}})})});var s=$("#tags");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselecttags/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);s.append(a).trigger("change"),s.trigger({type:"select2:select",params:{data:t}})})})}function handleButtonPress(){$("#search-form").submit(function(e){$("#status").html('<span class="label label-info">Loading data</span>'),e.preventDefault();var t=$("#name").val(),a=$("#device-roles").val(),n=$("#sites").val(),s=$("#tags").val();$.ajax({type:"GET",url:"../../api/plugins/topology-views/search/search/",data:{name:t,"devicerole[]":a,"sites[]":n,"tags[]":s},headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",dataType:"json",success:function(e){$("#status").html('<span class="label label-info">Drawing network</span>'),graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),$.each(e.nodes,function(e,t){nodes.add(t)}),$.each(e.edges,function(e,t){edges.add(t)}),graph.fit(),canvas=document.getElementById("visgraph").getElementsByTagName("canvas")[0],graph.on("afterDrawing",function(){$("#status").html('<span class="label label-success">Ready</span>');var e=canvas.toDataURL(MIME_TYPE);downloadButton.href=e,downloadButton.download="topology"}),graph.on("dragEnd",function(e){dragged=this.getPositions(e.nodes),$.each(dragged,function(e,t){$("#coordstatus").html(""),$("#checkSaveCoordinates").is(":checked")&&$.ajax({url:"../../api/plugins/topology-views/save-coords/save_coords/",type:"POST",dataType:"json",headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",data:JSON.stringify({node_id:e,x:t.x,y:t.y}),error:function(e){$("#coordstatus").html('<span class="label label-warning">Failed to update coordinates</span>')},success:function(e){$("#coordstatus").html('<span class="label label-success">Updated coordinates</span>')}})})})},error:function(e){$("#status").html('<span class="label label-warning">Something went wrong</span>')}})})}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
var graph = null;
|
var graph = null;
|
||||||
var container = null;
|
var container = null;
|
||||||
|
var downloadButton = null;
|
||||||
|
var MIME_TYPE = "image/png";
|
||||||
|
var canvas = null;
|
||||||
var csrftoken = null;
|
var csrftoken = null;
|
||||||
var nodes = new vis.DataSet();
|
var nodes = new vis.DataSet();
|
||||||
var edges = new vis.DataSet();
|
var edges = new vis.DataSet();
|
||||||
@@ -36,6 +39,7 @@ function iniPlotboxIndex() {
|
|||||||
csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||||
startLoadSearchBar();
|
startLoadSearchBar();
|
||||||
handleButtonPress();
|
handleButtonPress();
|
||||||
|
downloadButton = document.getElementById('btnDownloadImage');
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +171,14 @@ function handleButtonPress() {
|
|||||||
var value3 = $("#sites").val();
|
var value3 = $("#sites").val();
|
||||||
var value4 = $("#tags").val();
|
var value4 = $("#tags").val();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "GET",
|
||||||
url: "../../api/plugins/topology-views/search/search/",
|
url: "../../api/plugins/topology-views/search/search/",
|
||||||
data: JSON.stringify({
|
data: {
|
||||||
'name': value,
|
'name': value,
|
||||||
'devicerole': value2,
|
'devicerole[]': value2,
|
||||||
'sites': value3,
|
'sites[]': value3,
|
||||||
'tags': value4
|
'tags[]': value4
|
||||||
}),
|
},
|
||||||
headers: { "X-CSRFToken": csrftoken },
|
headers: { "X-CSRFToken": csrftoken },
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
@@ -191,9 +195,13 @@ function handleButtonPress() {
|
|||||||
edges.add(edge);
|
edges.add(edge);
|
||||||
});
|
});
|
||||||
graph.fit();
|
graph.fit();
|
||||||
|
canvas = document.getElementById('visgraph').getElementsByTagName('canvas')[0];
|
||||||
|
|
||||||
graph.on('afterDrawing', function () {
|
graph.on('afterDrawing', function () {
|
||||||
$("#status").html('<span class="label label-success">Ready</span>');
|
$("#status").html('<span class="label label-success">Ready</span>');
|
||||||
|
var image = canvas.toDataURL(MIME_TYPE);
|
||||||
|
downloadButton.href = image;
|
||||||
|
downloadButton.download = "topology";
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.on("dragEnd", function (params) {
|
graph.on("dragEnd", function (params) {
|
||||||
@@ -223,6 +231,7 @@ function handleButtonPress() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
error: function (error_result) {
|
error: function (error_result) {
|
||||||
$("#status").html('<span class="label label-warning">Something went wrong</span>');
|
$("#status").html('<span class="label label-warning">Something went wrong</span>');
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<strong>Network</strong> <span id="status"></span>
|
<strong>Network</strong> <span id="status"></span>
|
||||||
|
<div class="buttons pull-right">
|
||||||
|
<a id="btnDownloadImage" class="btn btn-xs btn-info">
|
||||||
|
<i class="fa fa-download"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="visgraph" class=""></div>
|
<div id="visgraph" class=""></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user