mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #3485: Enable embedded graphs for devices
This commit is contained in:
@ -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
|
||||||
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -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'),
|
||||||
)
|
)
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
Reference in New Issue
Block a user