Bladeren bron

Closes #3485: Enable embedded graphs for devices

Jeremy Stretch 6 jaren geleden
bovenliggende
commit
51fb0b59ec

+ 1 - 0
CHANGELOG.md

@@ -6,6 +6,7 @@ v2.6.4 (FUTURE)
 * [#3027](https://github.com/netbox-community/netbox/issues/3028) - Add `local_context_data` boolean filter for devices
 * [#3027](https://github.com/netbox-community/netbox/issues/3028) - Add `local_context_data` boolean filter for devices
 * [#3318](https://github.com/netbox-community/netbox/issues/3318) - Increase length of platform name and slug to 100 characters
 * [#3318](https://github.com/netbox-community/netbox/issues/3318) - Increase length of platform name and slug to 100 characters
 * [#3341](https://github.com/netbox-community/netbox/issues/3341) - Enable inline VLAN assignment while editing an interface
 * [#3341](https://github.com/netbox-community/netbox/issues/3341) - Enable inline VLAN assignment while editing an interface
+* [#3485](https://github.com/netbox-community/netbox/issues/3485) - Enable embedded graphs for devices
 * [#3510](https://github.com/netbox-community/netbox/issues/3510) - Add minimum/maximum prefix length enforcement for `IPNetworkVar`
 * [#3510](https://github.com/netbox-community/netbox/issues/3510) - Add minimum/maximum prefix length enforcement for `IPNetworkVar`
 
 
 ## Bug Fixes
 ## Bug Fixes

+ 1 - 1
netbox/circuits/api/views.py

@@ -35,7 +35,7 @@ class ProviderViewSet(CustomFieldModelViewSet):
     filterset_class = filters.ProviderFilter
     filterset_class = filters.ProviderFilter
 
 
     @action(detail=True)
     @action(detail=True)
-    def graphs(self, request, pk=None):
+    def graphs(self, request, pk):
         """
         """
         A convenience method for rendering graphs for a particular provider.
         A convenience method for rendering graphs for a particular provider.
         """
         """

+ 15 - 3
netbox/dcim/api/views.py

@@ -23,7 +23,8 @@ from dcim.models import (
 )
 )
 from extras.api.serializers import RenderedGraphSerializer
 from extras.api.serializers import RenderedGraphSerializer
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
-from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
+from extras.constants import GRAPH_TYPE_DEVICE, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
+from extras.models import Graph
 from ipam.models import Prefix, VLAN
 from ipam.models import Prefix, VLAN
 from utilities.api import (
 from utilities.api import (
     get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
     get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
@@ -123,7 +124,7 @@ class SiteViewSet(CustomFieldModelViewSet):
     filterset_class = filters.SiteFilter
     filterset_class = filters.SiteFilter
 
 
     @action(detail=True)
     @action(detail=True)
-    def graphs(self, request, pk=None):
+    def graphs(self, request, pk):
         """
         """
         A convenience method for rendering graphs for a particular site.
         A convenience method for rendering graphs for a particular site.
         """
         """
@@ -346,6 +347,17 @@ class DeviceViewSet(CustomFieldModelViewSet):
 
 
         return serializers.DeviceWithConfigContextSerializer
         return serializers.DeviceWithConfigContextSerializer
 
 
+    @action(detail=True)
+    def graphs(self, request, pk):
+        """
+        A convenience method for rendering graphs for a particular Device.
+        """
+        device = get_object_or_404(Device, pk=pk)
+        queryset = Graph.objects.filter(type=GRAPH_TYPE_DEVICE)
+        serializer = RenderedGraphSerializer(queryset, many=True, context={'graphed_object': device})
+
+        return Response(serializer.data)
+
     @action(detail=True, url_path='napalm')
     @action(detail=True, url_path='napalm')
     def napalm(self, request, pk):
     def napalm(self, request, pk):
         """
         """
@@ -458,7 +470,7 @@ class InterfaceViewSet(CableTraceMixin, ModelViewSet):
     filterset_class = filters.InterfaceFilter
     filterset_class = filters.InterfaceFilter
 
 
     @action(detail=True)
     @action(detail=True)
-    def graphs(self, request, pk=None):
+    def graphs(self, request, pk):
         """
         """
         A convenience method for rendering graphs for a particular interface.
         A convenience method for rendering graphs for a particular interface.
         """
         """

+ 4 - 5
netbox/dcim/views.py

@@ -16,7 +16,8 @@ from django.utils.safestring import mark_safe
 from django.views.generic import View
 from django.views.generic import View
 
 
 from circuits.models import Circuit
 from circuits.models import Circuit
-from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
+from extras.constants import GRAPH_TYPE_DEVICE, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
+from extras.models import Graph, TopologyMap
 from extras.views import ObjectConfigContextView
 from extras.views import ObjectConfigContextView
 from ipam.models import Prefix, VLAN
 from ipam.models import Prefix, VLAN
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
@@ -972,9 +973,6 @@ class DeviceView(PermissionRequiredMixin, View):
             'rack', 'device_type__manufacturer'
             'rack', 'device_type__manufacturer'
         )[:10]
         )[:10]
 
 
-        # Show graph button on interfaces only if at least one graph has been created.
-        show_graphs = Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists()
-
         return render(request, 'dcim/device.html', {
         return render(request, 'dcim/device.html', {
             'device': device,
             'device': device,
             'console_ports': console_ports,
             'console_ports': console_ports,
@@ -989,7 +987,8 @@ class DeviceView(PermissionRequiredMixin, View):
             'secrets': secrets,
             'secrets': secrets,
             'vc_members': vc_members,
             'vc_members': vc_members,
             'related_devices': related_devices,
             'related_devices': related_devices,
-            'show_graphs': show_graphs,
+            'show_graphs': Graph.objects.filter(type=GRAPH_TYPE_DEVICE).exists(),
+            'show_interface_graphs': Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists(),
         })
         })
 
 
 
 

+ 2 - 0
netbox/extras/constants.py

@@ -88,10 +88,12 @@ BUTTON_CLASS_CHOICES = (
 
 
 # Graph types
 # Graph types
 GRAPH_TYPE_INTERFACE = 100
 GRAPH_TYPE_INTERFACE = 100
+GRAPH_TYPE_DEVICE = 150
 GRAPH_TYPE_PROVIDER = 200
 GRAPH_TYPE_PROVIDER = 200
 GRAPH_TYPE_SITE = 300
 GRAPH_TYPE_SITE = 300
 GRAPH_TYPE_CHOICES = (
 GRAPH_TYPE_CHOICES = (
     (GRAPH_TYPE_INTERFACE, 'Interface'),
     (GRAPH_TYPE_INTERFACE, 'Interface'),
+    (GRAPH_TYPE_DEVICE, 'Device'),
     (GRAPH_TYPE_PROVIDER, 'Provider'),
     (GRAPH_TYPE_PROVIDER, 'Provider'),
     (GRAPH_TYPE_SITE, 'Site'),
     (GRAPH_TYPE_SITE, 'Site'),
 )
 )

+ 6 - 0
netbox/templates/dcim/device.html

@@ -35,6 +35,12 @@
         </div>
         </div>
     </div>
     </div>
     <div class="pull-right noprint">
     <div class="pull-right noprint">
+        {% if show_graphs %}
+            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }}" data-url="{% url 'dcim-api:device-graphs' pk=device.pk %}" title="Show graphs">
+                <i class="fa fa-signal" aria-hidden="true"></i>
+                Graphs
+            </button>
+        {% endif %}
         {% if perms.dcim.change_device %}
         {% if perms.dcim.change_device %}
             <div class="btn-group">
             <div class="btn-group">
                 <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                 <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">

+ 1 - 1
netbox/templates/dcim/inc/interface.html

@@ -135,7 +135,7 @@
 
 
     {# Buttons #}
     {# Buttons #}
     <td class="text-right text-nowrap noprint">
     <td class="text-right text-nowrap noprint">
-        {% if show_graphs %}
+        {% if show_interface_graphs %}
             {% if iface.connected_endpoint %}
             {% if iface.connected_endpoint %}
                 <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }} - {{ iface.name }}" data-url="{% url 'dcim-api:interface-graphs' pk=iface.pk %}" title="Show graphs">
                 <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }} - {{ iface.name }}" data-url="{% url 'dcim-api:interface-graphs' pk=iface.pk %}" title="Show graphs">
                     <i class="glyphicon glyphicon-signal" aria-hidden="true"></i>
                     <i class="glyphicon glyphicon-signal" aria-hidden="true"></i>