Browse Source

#878: Show assigned IP addresses in device interfaces list

Jeremy Stretch 8 years ago
parent
commit
d5c3f9e780

+ 1 - 1
netbox/dcim/forms.py

@@ -1713,7 +1713,7 @@ class IPAddressForm(BootstrapMixin, CustomFieldForm):
         self.fields['interface'].required = True
 
         # If this device has only one interface, select it by default.
-        if len(interfaces) == 1:
+        if 'interface' not in self.initial and len(interfaces) == 1:
             self.fields['interface'].initial = interfaces[0]
 
         # If this device does not have any IP addresses assigned, default to setting the first IP as its primary.

+ 4 - 9
netbox/dcim/views.py

@@ -13,7 +13,7 @@ from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.http import urlencode
 from django.views.generic import View
 
-from ipam.models import Prefix, IPAddress, Service, VLAN
+from ipam.models import Prefix, Service, VLAN
 from circuits.models import Circuit
 from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
 from utilities.forms import ConfirmationForm
@@ -700,19 +700,15 @@ def device(request, pk):
     interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
         .filter(device=device, mgmt_only=False)\
         .select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
-                        'circuit_termination__circuit')
+                        'circuit_termination__circuit').prefetch_related('ip_addresses')
     mgmt_interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
         .filter(device=device, mgmt_only=True)\
         .select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
-                        'circuit_termination__circuit')
+                        'circuit_termination__circuit').prefetch_related('ip_addresses')
     device_bays = natsorted(
         DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer'),
         key=attrgetter('name')
     )
-
-    # Gather relevant device objects
-    ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface', 'vrf')\
-        .order_by('address')
     services = Service.objects.filter(device=device)
     secrets = device.secrets.all()
 
@@ -743,7 +739,6 @@ def device(request, pk):
         'interfaces': interfaces,
         'mgmt_interfaces': mgmt_interfaces,
         'device_bays': device_bays,
-        'ip_addresses': ip_addresses,
         'services': services,
         'secrets': secrets,
         'related_devices': related_devices,
@@ -1599,7 +1594,7 @@ def ipaddress_assign(request, pk):
                 return redirect('dcim:device', pk=device.pk)
 
     else:
-        form = forms.IPAddressForm(device)
+        form = forms.IPAddressForm(device, initial=request.GET)
 
     return render(request, 'dcim/ipaddress_assign.html', {
         'device': device,

+ 10 - 0
netbox/project-static/css/base.css

@@ -313,6 +313,16 @@ li.occupied + li.available {
     border-top: 1px solid #474747;
 }
 
+/* Devices */
+table.component-list tr.ipaddress td {
+    background-color: #eeffff;
+    padding-bottom: 4px;
+    padding-top: 4px;
+}
+table.component-list tr.ipaddress:hover td {
+    background-color: #e6f7f7;
+}
+
 /* Misc */
 .banner-bottom {
     margin-bottom: 50px;

+ 20 - 34
netbox/templates/dcim/device.html

@@ -196,35 +196,6 @@
         {% endif %}
         <div class="panel panel-default">
             <div class="panel-heading">
-                <strong>IP Addresses</strong>
-            </div>
-            {% if ip_addresses %}
-                <table class="table table-hover panel-body">
-                    {% for ip in ip_addresses %}
-                        {% include 'dcim/inc/ipaddress.html' %}
-                    {% endfor %}
-                </table>
-            {% elif interfaces or mgmt_interfaces %}
-                <div class="panel-body text-muted">
-                    None assigned
-                </div>
-            {% else %}
-                <div class="panel-body">
-                    <a href="{% url 'dcim:interface_add' pk=device.pk %}">Create an interface</a> to assign an IP.
-                </div>
-            {% endif %}
-            {% if perms.ipam.add_ipaddress %}
-                {% if interfaces or mgmt_interfaces %}
-                    <div class="panel-footer text-right">
-                        <a href="{% url 'dcim:ipaddress_assign' pk=device.pk %}" class="btn btn-xs btn-primary">
-                            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Assign IP address
-                        </a>
-                    </div>
-                {% endif %}
-            {% endif %}
-        </div>
-        <div class="panel panel-default">
-            <div class="panel-heading">
                 <strong>Services</strong>
             </div>
             {% if services %}
@@ -250,7 +221,7 @@
             <div class="panel-heading">
                 <strong>Critical Connections</strong>
             </div>
-            <table class="table table-hover panel-body">
+            <table class="table table-hover panel-body component-list">
                 {% for iface in mgmt_interfaces %}
                     {% include 'dcim/inc/interface.html' with icon='wrench' %}
                 {% empty %}
@@ -375,7 +346,7 @@
                         {% endif %}
                     </div>
                 </div>
-                <table class="table table-hover panel-body">
+                <table class="table table-hover panel-body component-list">
                     {% for devicebay in device_bays %}
                         {% include 'dcim/inc/devicebay.html' with selectable=True %}
                     {% empty %}
@@ -416,6 +387,9 @@
                 <div class="panel-heading">
                     <strong>Interfaces</strong>
                     <div class="pull-right">
+                        <button class="btn btn-default btn-xs toggle-ips" selected="selected">
+                            <span class="glyphicon glyphicon-check" aria-hidden="true"></span> Show IPs
+                        </button>
                         {% if perms.dcim.change_interface and interfaces|length > 1 %}
                             <button class="btn btn-default btn-xs toggle">
                                 <span class="glyphicon glyphicon-unchecked" aria-hidden="true"></span> Select all
@@ -428,7 +402,7 @@
                         {% endif %}
                     </div>
                 </div>
-                <table class="table table-hover panel-body">
+                <table class="table table-hover panel-body component-list">
                     {% for iface in interfaces %}
                         {% include 'dcim/inc/interface.html' with selectable=True %}
                     {% empty %}
@@ -485,7 +459,7 @@
                         {% endif %}
                     </div>
                 </div>
-                <table class="table table-hover panel-body">
+                <table class="table table-hover panel-body component-list">
                     {% for csp in cs_ports %}
                         {% include 'dcim/inc/consoleserverport.html' with selectable=True %}
                     {% empty %}
@@ -537,7 +511,7 @@
                         {% endif %}
                     </div>
                 </div>
-                <table class="table table-hover panel-body">
+                <table class="table table-hover panel-body component-list">
                     {% for po in power_outlets %}
                         {% include 'dcim/inc/poweroutlet.html' with selectable=True %}
                     {% empty %}
@@ -628,6 +602,18 @@ $(".powerport-toggle").click(function() {
 $(".interface-toggle").click(function() {
     return toggleConnection($(this), "dcim/interface-connections/");
 });
+// Toggle the display of IP addresses under interfaces
+$('button.toggle-ips').click(function() {
+    var selected = $(this).attr('selected');
+    if (selected) {
+        $('table.component-list tr.ipaddress').hide();
+    } else {
+        $('table.component-list tr.ipaddress').show();
+    }
+    $(this).attr('selected', !selected);
+    $(this).children('span').toggleClass('glyphicon-check glyphicon-unchecked');
+    return false;
+});
 </script>
 <script src="{% static 'js/graphs.js' %}"></script>
 <script src="{% static 'js/secrets.js' %}"></script>

+ 49 - 9
netbox/templates/dcim/inc/interface.html

@@ -1,4 +1,4 @@
-<tr{% if iface.connection and not iface.connection.connection_status %} class="info"{% endif %}>
+<tr class="interface{% if iface.connection and not iface.connection.connection_status %} info{% endif %}">
     {% if selectable and perms.dcim.change_interface or perms.dcim.delete_interface %}
         <td class="pk">
             <input name="pk" type="checkbox" value="{{ iface.pk }}" />
@@ -16,9 +16,6 @@
             <br /><small class="text-muted">{{ iface.member_interfaces.all|join:", "|default:"No members" }}</small>
         {% endif %}
     </td>
-    <td>
-        <small>{{ iface.mac_address|default:'' }}</small>
-    </td>
     {% if iface.is_lag %}
         <td colspan="2" class="text-muted">LAG interface</td>
     {% elif iface.is_virtual %}
@@ -53,7 +50,7 @@
             <span class="text-muted">Not connected</span>
         </td>
     {% endif %}
-    <td class="text-right">
+    <td colspan="2" class="text-right">
         {% if show_graphs %}
             {% if iface.circuit_termination or iface.connection %}
                 <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">
@@ -61,6 +58,11 @@
                 </button>
             {% endif %}
         {% endif %}
+        {% if perms.ipam.add_ipaddress %}
+            <a href="{% url 'dcim:ipaddress_assign' pk=device.pk %}?interface={{ iface.pk }}" class="btn btn-xs btn-success" title="Assign IP address">
+                <i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
+            </a>
+        {% endif %}
         {% if perms.dcim.change_interface %}
             {% if not iface.is_virtual %}
                 {% if iface.connection %}
@@ -73,19 +75,19 @@
                             <i class="fa fa-plug" aria-hidden="true"></i>
                         </a>
                     {% endif %}
-                    <a href="{% url 'dcim:interfaceconnection_delete' pk=iface.connection.pk %}?device={{ device.pk }}" class="btn btn-danger btn-xs" title="Delete connection">
-                        <i class="glyphicon glyphicon-remove" aria-hidden="true"></i>
+                    <a href="{% url 'dcim:interfaceconnection_delete' pk=iface.connection.pk %}?device={{ device.pk }}" class="btn btn-danger btn-xs" title="Disconnect">
+                        <i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
                     </a>
                 {% elif iface.circuit_termination and perms.circuits.change_circuittermination %}
                     <button class="btn btn-warning btn-xs interface-toggle connected" disabled="disabled" title="Circuits cannot be marked as planned or connected">
                         <i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
                     </button>
                     <a href="{% url 'circuits:circuittermination_edit' pk=iface.circuit_termination.pk %}" class="btn btn-danger btn-xs" title="Edit circuit termination">
-                        <i class="glyphicon glyphicon-remove" aria-hidden="true"></i>
+                        <i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
                     </a>
                 {% else %}
                     <a href="{% url 'dcim:interfaceconnection_add' pk=device.pk %}?interface_a={{ iface.pk }}" class="btn btn-success btn-xs" title="Connect">
-                        <i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
+                        <i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
                     </a>
                 {% endif %}
             {% endif %}
@@ -106,3 +108,41 @@
         {% endif %}
     </td>
 </tr>
+{% for ip in iface.ip_addresses.all %}
+    <tr class="ipaddress">
+        {% if selectable and perms.dcim.change_interface or perms.dcim.delete_interface %}
+            <td></td>
+        {% endif %}
+        <td colspan="2">
+            <a href="{% url 'ipam:ipaddress' pk=ip.pk %}">{{ ip }}</a>
+            {% if ip.description %}
+                <i class="fa fa-fw fa-comment-o" title="{{ ip.description }}"></i>
+            {% endif %}
+            {% if device.primary_ip4 == ip or device.primary_ip6 == ip %}
+                <span class="label label-success">Primary</span>
+            {% endif %}
+        </td>
+        <td class="text-right">
+            {% if ip.vrf %}
+                <a href="{% url 'ipam:vrf' pk=ip.vrf.pk %}">{{ ip.vrf }}</a>
+            {% else %}
+                <span class="text-muted">Global</span>
+            {% endif %}
+        </td>
+        <td>
+            <span class="label label-{{ ip.get_status_class }}">{{ ip.get_status_display }}</span>
+        </td>
+        <td class="text-right">
+            {% if perms.ipam.edit_ipaddress %}
+                <a href="{% url 'ipam:ipaddress_edit' pk=ip.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-info btn-xs">
+                    <i class="glyphicon glyphicon-pencil" aria-hidden="true" title="Edit IP address"></i>
+                </a>
+            {% endif %}
+            {% if perms.ipam.delete_ipaddress %}
+                <a href="{% url 'ipam:ipaddress_delete' pk=ip.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
+                    <i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete IP address"></i>
+                </a>
+            {% endif %}
+        </td>
+    </tr>
+{% endfor %}

+ 0 - 21
netbox/templates/dcim/inc/ipaddress.html

@@ -1,21 +0,0 @@
-<tr>
-    <td>
-        <a href="{% url 'ipam:ipaddress' pk=ip.pk %}">{{ ip }}</a>
-    </td>
-    <td>
-        {{ ip.vrf|default:"Global" }}
-    </td>
-    <td>{{ ip.interface }}</td>
-    <td>
-        {% if device.primary_ip4 == ip or device.primary_ip6 == ip %}
-            <span class="label label-success">Primary</span>
-        {% endif %}
-    </td>
-    <td class="text-right">
-        {% if perms.ipam.delete_ipaddress %}
-            <a href="{% url 'ipam:ipaddress_delete' pk=ip.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
-                <i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete IP address"></i>
-            </a>
-        {% endif %}
-    </td>
-</tr>