Просмотр исходного кода

Convert device interfaces list to table

Jeremy Stretch 5 лет назад
Родитель
Сommit
2146c38748

+ 28 - 1
netbox/dcim/tables/devices.py

@@ -11,7 +11,7 @@ from utilities.tables import (
     TagColumn, ToggleColumn,
 )
 from .template_code import (
-    CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, FRONTPORT_BUTTONS,
+    CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, FRONTPORT_BUTTONS, INTERFACE_BUTTONS,
     INTERFACE_IPADDRESSES, INTERFACE_TAGGED_VLANS, POWEROUTLET_BUTTONS, POWERPORT_BUTTONS, REARPORT_BUTTONS,
 )
 
@@ -23,6 +23,7 @@ __all__ = (
     'DeviceConsoleServerPortTable',
     'DeviceFrontPortTable',
     'DeviceImportTable',
+    'DeviceInterfaceTable',
     'DevicePowerPortTable',
     'DevicePowerOutletTable',
     'DeviceRearPortTable',
@@ -405,6 +406,32 @@ class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable
         default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
 
 
+class DeviceInterfaceTable(InterfaceTable):
+    name = tables.TemplateColumn(
+        template_code='<i class="fa fa-{% if iface.mgmt_only %}wrench{% elif iface.is_lag %}align-justify'
+                      '{% elif iface.is_virtual %}circle{% elif iface.is_wireless %}wifi{% else %}exchange'
+                      '{% endif %}"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>'
+    )
+    actions = ButtonsColumn(
+        model=Interface,
+        buttons=('edit', 'delete'),
+        prepend_template=INTERFACE_BUTTONS
+    )
+
+    class Meta(DeviceComponentTable.Meta):
+        model = Interface
+        fields = (
+            'pk', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'description', 'cable',
+            'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans', 'actions',
+        )
+        default_columns = (
+            'pk', 'name', 'label', 'type', 'enabled', 'description', 'cable', 'cable_peer', 'actions',
+        )
+        row_attrs = {
+            'class': lambda record: record.cable.get_status_class() if record.cable else ''
+        }
+
+
 class FrontPortTable(DeviceComponentTable, CableTerminationTable):
     rear_port_position = tables.Column(
         verbose_name='Position'

+ 25 - 0
netbox/dcim/tables/template_code.py

@@ -138,6 +138,31 @@ POWEROUTLET_BUTTONS = """
 {% endif %}
 """
 
+INTERFACE_BUTTONS = """
+{% if perms.ipam.add_ipaddress %}
+    <a href="{% url 'ipam:ipaddress_add' %}?interface={{ record.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-success" title="Add IP address">
+        <i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
+    </a>
+{% endif %}
+{% if perms.dcim.change_interface %}
+    {% if record.cable %}
+        {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+    {% elif record.is_connectable and perms.dcim.add_cable %}
+        <span class="dropdown">
+            <button type="button" class="btn btn-success btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <span class="glyphicon glyphicon-resize-small" aria-hidden="true"></span>
+            </button>
+            <ul class="dropdown-menu dropdown-menu-right">
+                <li><a href="{% url 'dcim:interface_connect' termination_a_id=record.pk termination_b_type='interface' %}?return_url={{ device.get_absolute_url }}">Interface</a></li>
+                <li><a href="{% url 'dcim:interface_connect' termination_a_id=record.pk termination_b_type='front-port' %}?return_url={{ device.get_absolute_url }}">Front Port</a></li>
+                <li><a href="{% url 'dcim:interface_connect' termination_a_id=record.pk termination_b_type='rear-port' %}?return_url={{ device.get_absolute_url }}">Rear Port</a></li>
+                <li><a href="{% url 'dcim:interface_connect' termination_a_id=record.pk termination_b_type='circuit-termination' %}?return_url={{ device.get_absolute_url }}">Circuit Termination</a></li>
+            </ul>
+        </span>
+    {% endif %}
+{% endif %}
+"""
+
 FRONTPORT_BUTTONS = """
 {% if frontport.cable %}
     {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}

+ 4 - 1
netbox/dcim/views.py

@@ -1056,6 +1056,9 @@ class DeviceView(ObjectView):
             Prefetch('member_interfaces', queryset=Interface.objects.restrict(request.user)),
             'lag', 'cable', '_path__destination', 'tags',
         )
+        interface_table = tables.DeviceInterfaceTable(interfaces, orderable=False)
+        if request.user.has_perm('dcim.change_interface') or request.user.has_perm('dcim.delete_interface'):
+            interface_table.columns.show('pk')
 
         # Front ports
         frontports = FrontPort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related(
@@ -1102,7 +1105,7 @@ class DeviceView(ObjectView):
             'consoleserverport_table': consoleserverport_table,
             'powerport_table': powerport_table,
             'poweroutlet_table': poweroutlet_table,
-            'interfaces': interfaces,
+            'interface_table': interface_table,
             'frontport_table': frontport_table,
             'rearport_table': rearport_table,
             'devicebays': devicebays,

+ 2 - 24
netbox/templates/dcim/device.html

@@ -122,7 +122,7 @@
                     <a href="#details" role="tab" data-toggle="tab">Details</a>
                 </li>
                 <li role="presentation">
-                    <a href="#interfaces" role="tab" data-toggle="tab">Interfaces {% badge interfaces|length %}</a>
+                    <a href="#interfaces" role="tab" data-toggle="tab">Interfaces {% badge interface_table.rows|length %}</a>
                 </li>
                 <li role="presentation">
                     <a href="#frontports" role="tab" data-toggle="tab">Front Ports {% badge frontport_table.rows|length %}</a>
@@ -494,29 +494,7 @@
                                     <input class="form-control interface-filter" type="text" placeholder="Filter" title="Filter text (regular expressions supported)" style="height: 23px" />
                                 </div>
                             </div>
-                            <table id="interfaces_table" class="table table-hover table-headings panel-body component-list">
-                                <thead>
-                                    <tr>
-                                        {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
-                                            <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
-                                        {% endif %}
-                                        <th>Name</th>
-                                        <th>LAG</th>
-                                        <th>Description</th>
-                                        <th>MTU</th>
-                                        <th>Mode</th>
-                                        <th>Cable</th>
-                                        <th colspan="2">Cable Termination</th>
-                                        <th colspan="2">Connection</th>
-                                        <th></th>
-                                    </tr>
-                                </thead>
-                                <tbody>
-                                    {% for iface in interfaces %}
-                                        {% include 'dcim/inc/interface.html' %}
-                                    {% endfor %}
-                                </tbody>
-                            </table>
+                            {% include 'responsive_table.html' with table=interface_table %}
                             <div class="panel-footer noprint">
                                 {% if interfaces and perms.dcim.change_interface %}
                                     <button type="submit" name="_rename" formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">

+ 0 - 200
netbox/templates/dcim/inc/interface.html

@@ -1,200 +0,0 @@
-{% load helpers %}
-<tr class="interface{% if not iface.enabled %} danger{% elif iface.cable %} {{ iface.cable.get_status_class }}{% elif iface.is_virtual %} warning{% endif %}" id="interface_{{ iface.name }}">
-
-    {# Checkbox #}
-    {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
-        <td class="pk">
-            <input name="pk" type="checkbox" value="{{ iface.pk }}" />
-        </td>
-    {% endif %}
-
-    {# Icon and name #}
-    <td class="text-nowrap">
-        <span title="{{ iface.get_type_display }}">
-            <i class="fa fa-fw fa-{% if iface.mgmt_only %}wrench{% elif iface.is_lag %}align-justify{% elif iface.is_virtual %}circle{% elif iface.is_wireless %}wifi{% else %}exchange{% endif %}"></i>
-            <a href="{{ iface.get_absolute_url }}">{{ iface }}</a>
-        </span>
-        {% if iface.mac_address %}
-            <br/><small class="text-muted">{{ iface.mac_address }}</small>
-        {% endif %}
-    </td>
-
-    {# LAG #}
-    <td>
-        {% if iface.lag %}
-            <a href="{{ iface.lag.device.get_absolute_url }}#interface_{{ iface.lag }}" class="label label-primary" title="{{ iface.lag.description }}">{{ iface.lag }}</a>
-        {% endif %}
-    </td>
-
-    {# Description/tags #}
-    <td>
-        {% if iface.description %}
-            {{ iface.description }}<br/>
-        {% endif %}
-        {% for tag in iface.tags.all %}
-            {% tag tag %}
-        {% empty %}
-            {% if not iface.description %}&mdash;{% endif %}
-        {% endfor %}
-    </td>
-
-    {# MTU #}
-    <td>{{ iface.mtu|default:"&mdash;" }}</td>
-
-    {# 802.1Q mode #}
-    <td>{{ iface.get_mode_display|default:"&mdash;" }}</td>
-
-    {# Cable #}
-    {% if iface.cable %}
-        <td>
-            <a href="{{ iface.cable.get_absolute_url }}">{{ iface.cable }}</a>
-            <a href="{% url 'dcim:interface_trace' pk=iface.pk %}" class="btn btn-primary btn-xs" title="Trace">
-                <i class="fa fa-share-alt" aria-hidden="true"></i>
-            </a>
-        </td>
-        {% include 'dcim/inc/cabletermination.html' with termination=iface.get_cable_peer %}
-    {% else %}
-        <td colspan="3">
-            <span class="text-muted">Not connected</span>
-        </td>
-    {% endif %}
-
-    {# Connection or type #}
-    {% if iface.is_lag %}
-        <td colspan="2" class="text-muted">
-            LAG interface<br />
-            <small class="text-muted">
-                {% for member in iface.member_interfaces.all %}
-                    <a href="{{ member.get_absolute_url }}">{{ member }}</a>{% if not forloop.last %}, {% endif %}
-                {% empty %}
-                    No members
-                {% endfor %}
-            </small>
-        </td>
-    {% elif iface.is_virtual %}
-        <td colspan="2" class="text-muted">Virtual interface</td>
-    {% elif iface.is_wireless %}
-        <td colspan="2" class="text-muted">Wireless interface</td>
-    {% else %}
-        {% include 'dcim/inc/endpoint_connection.html' with path=iface.path %}
-    {% endif %}
-
-    {# Buttons #}
-    <td class="text-right text-nowrap noprint">
-        {% if perms.ipam.add_ipaddress %}
-            <a href="{% url 'ipam:ipaddress_add' %}?interface={{ iface.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-success" title="Add IP address">
-                <i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
-            </a>
-        {% endif %}
-        {% if perms.dcim.change_interface %}
-            {% if iface.cable %}
-                {% include 'dcim/inc/cable_toggle_buttons.html' with cable=iface.cable %}
-            {% elif iface.is_connectable and perms.dcim.add_cable %}
-                <span class="dropdown">
-                    <button type="button" class="btn btn-success btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <span class="glyphicon glyphicon-resize-small" aria-hidden="true"></span>
-                    </button>
-                    <ul class="dropdown-menu dropdown-menu-right">
-                        <li><a href="{% url 'dcim:interface_connect' termination_a_id=iface.pk termination_b_type='interface' %}?return_url={{ device.get_absolute_url }}">Interface</a></li>
-                        <li><a href="{% url 'dcim:interface_connect' termination_a_id=iface.pk termination_b_type='front-port' %}?return_url={{ device.get_absolute_url }}">Front Port</a></li>
-                        <li><a href="{% url 'dcim:interface_connect' termination_a_id=iface.pk termination_b_type='rear-port' %}?return_url={{ device.get_absolute_url }}">Rear Port</a></li>
-                        <li><a href="{% url 'dcim:interface_connect' termination_a_id=iface.pk termination_b_type='circuit-termination' %}?return_url={{ device.get_absolute_url }}">Circuit Termination</a></li>
-                    </ul>
-                </span>
-            {% endif %}
-            <a href="{% url 'dcim:interface_edit' pk=iface.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-info btn-xs" title="Edit interface">
-                <i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
-            </a>
-        {% endif %}
-        {% if perms.dcim.delete_interface %}
-            {% if iface.connection or iface.circuit_termination %}
-                <button class="btn btn-danger btn-xs" disabled="disabled">
-                    <i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
-                </button>
-            {% else %}
-                <a href="{% url 'dcim:interface_delete' pk=iface.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs" title="Delete interface">
-                    <i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
-                </a>
-            {% endif %}
-        {% endif %}
-    </td>
-</tr>
-
-{% with ipaddresses=iface.ip_addresses.all %}
-    {% if ipaddresses %}
-        <tr class="ipaddresses">
-            {# Placeholder #}
-            {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
-                <td></td>
-            {% endif %}
-
-            {# IP addresses table #}
-            <td colspan="9" style="padding: 0">
-                <table class="table table-condensed interface-ips">
-                    <thead>
-                        <tr class="text-muted">
-                            <th class="col-md-3">IP Address</th>
-                            <th class="col-md-2">Status/Role</th>
-                            <th class="col-md-3">VRF</th>
-                            <th class="col-md-3">Description</th>
-                            <th class="col-md-1"></th>
-                        </tr>
-                    </thead>
-                    {% for ip in iface.ip_addresses.all %}
-                        <tr>
-
-                            {# IP address #}
-                            <td>
-                                <a href="{% url 'ipam:ipaddress' pk=ip.pk %}">{{ ip }}</a>
-                            </td>
-
-                            {# Primary/status/role #}
-                            <td>
-                                {% if device.primary_ip4 == ip or device.primary_ip6 == ip %}
-                                    <span class="label label-success">Primary</span>
-                                {% endif %}
-                                <span class="label label-{{ ip.get_status_class }}">{{ ip.get_status_display }}</span>
-                                {% if ip.role %}
-                                    <span class="label label-{{ ip.get_role_class }}">{{ ip.get_role_display }}</span>
-                                {% endif %}
-                            </td>
-
-                            {# VRF #}
-                            <td>
-                                {% if ip.vrf %}
-                                    <a href="{% url 'ipam:vrf' pk=ip.vrf.pk %}" title="{{ ip.vrf.rd }}">{{ ip.vrf.name }}</a>
-                                {% else %}
-                                    <span class="text-muted">Global</span>
-                                {% endif %}
-                            </td>
-
-                            {# Description #}
-                            <td>
-                                {% if ip.description %}
-                                    {{ ip.description }}
-                                {% else %}
-                                    <span class="text-muted">&mdash;</span>
-                                {% endif %}
-                            </td>
-
-                            {# Buttons #}
-                            <td class="text-right text-nowrap noprint">
-                                {% if perms.ipam.change_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 %}
-                </table>
-            </td>
-        </tr>
-    {% endif %}
-{% endwith %}