diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py
index c614c534b..290fa6aa1 100644
--- a/netbox/dcim/tables/devices.py
+++ b/netbox/dcim/tables/devices.py
@@ -10,15 +10,28 @@ from utilities.tables import (
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
TagColumn, ToggleColumn,
)
-from .template_code import DEVICE_LINK, INTERFACE_IPADDRESSES, INTERFACE_TAGGED_VLANS
+from .template_code import (
+ CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
+ FRONTPORT_BUTTONS, INTERFACE_BUTTONS, INTERFACE_IPADDRESSES, INTERFACE_TAGGED_VLANS, POWEROUTLET_BUTTONS,
+ POWERPORT_BUTTONS, REARPORT_BUTTONS,
+)
__all__ = (
'ConsolePortTable',
'ConsoleServerPortTable',
- 'DeviceImportTable',
- 'DeviceTable',
'DeviceBayTable',
+ 'DeviceConsolePortTable',
+ 'DeviceConsoleServerPortTable',
+ 'DeviceDeviceBayTable',
+ 'DeviceFrontPortTable',
+ 'DeviceImportTable',
+ 'DeviceInterfaceTable',
+ 'DeviceInventoryItemTable',
+ 'DevicePowerPortTable',
+ 'DevicePowerOutletTable',
+ 'DeviceRearPortTable',
'DeviceRoleTable',
+ 'DeviceTable',
'FrontPortTable',
'InterfaceTable',
'InventoryItemTable',
@@ -204,29 +217,93 @@ class DeviceComponentTable(BaseTable):
order_by = ('device', 'name')
-class ConsolePortTable(DeviceComponentTable):
+class CableTerminationTable(BaseTable):
+ cable = tables.Column(
+ linkify=True
+ )
+ cable_peer = tables.TemplateColumn(
+ accessor='get_cable_peer',
+ template_code=CABLETERMINATION,
+ orderable=False
+ )
+
+
+class PathEndpointTable(CableTerminationTable):
+ connection = tables.TemplateColumn(
+ accessor='_path.destination',
+ template_code=CABLETERMINATION,
+ verbose_name='Connection',
+ orderable=False
+ )
+
+
+class ConsolePortTable(DeviceComponentTable, PathEndpointTable):
tags = TagColumn(
url_name='dcim:consoleport_list'
)
class Meta(DeviceComponentTable.Meta):
model = ConsolePort
- fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'tags')
+ fields = (
+ 'pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags',
+ )
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
-class ConsoleServerPortTable(DeviceComponentTable):
+class DeviceConsolePortTable(ConsolePortTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=ConsolePort,
+ buttons=('edit', 'delete'),
+ prepend_template=CONSOLEPORT_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = ConsolePort
+ fields = (
+ 'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
+ )
+ default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
+class ConsoleServerPortTable(DeviceComponentTable, PathEndpointTable):
tags = TagColumn(
url_name='dcim:consoleserverport_list'
)
class Meta(DeviceComponentTable.Meta):
model = ConsoleServerPort
- fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'tags')
+ fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
-class PowerPortTable(DeviceComponentTable):
+class DeviceConsoleServerPortTable(ConsoleServerPortTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=ConsoleServerPort,
+ buttons=('edit', 'delete'),
+ prepend_template=CONSOLESERVERPORT_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = ConsoleServerPort
+ fields = (
+ 'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
+ )
+ default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
+class PowerPortTable(DeviceComponentTable, PathEndpointTable):
tags = TagColumn(
url_name='dcim:powerport_list'
)
@@ -234,22 +311,78 @@ class PowerPortTable(DeviceComponentTable):
class Meta(DeviceComponentTable.Meta):
model = PowerPort
fields = (
- 'pk', 'device', 'name', 'label', 'type', 'description', 'maximum_draw', 'allocated_draw', 'cable', 'tags',
+ 'pk', 'device', 'name', 'label', 'type', 'description', 'maximum_draw', 'allocated_draw', 'cable',
+ 'cable_peer', 'connection', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
-class PowerOutletTable(DeviceComponentTable):
+class DevicePowerPortTable(PowerPortTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=PowerPort,
+ buttons=('edit', 'delete'),
+ prepend_template=POWERPORT_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = PowerPort
+ fields = (
+ 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'cable_peer',
+ 'connection', 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'connection',
+ 'actions',
+ )
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
+class PowerOutletTable(DeviceComponentTable, PathEndpointTable):
+ power_port = tables.Column(
+ linkify=True
+ )
tags = TagColumn(
url_name='dcim:poweroutlet_list'
)
class Meta(DeviceComponentTable.Meta):
model = PowerOutlet
- fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'cable', 'tags')
+ fields = (
+ 'pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'cable', 'cable_peer',
+ 'connection', 'tags',
+ )
default_columns = ('pk', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description')
+class DevicePowerOutletTable(PowerOutletTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=PowerOutlet,
+ buttons=('edit', 'delete'),
+ prepend_template=POWEROUTLET_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = PowerOutlet
+ fields = (
+ 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'cable_peer', 'connection',
+ 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'connection', 'actions',
+ )
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
class BaseInterfaceTable(BaseTable):
enabled = BooleanColumn()
ip_addresses = tables.TemplateColumn(
@@ -265,7 +398,7 @@ class BaseInterfaceTable(BaseTable):
)
-class InterfaceTable(DeviceComponentTable, BaseInterfaceTable):
+class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable):
tags = TagColumn(
url_name='dcim:interface_list'
)
@@ -274,15 +407,49 @@ class InterfaceTable(DeviceComponentTable, BaseInterfaceTable):
model = Interface
fields = (
'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address',
- 'description', 'cable', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
+ 'description', 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
)
default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
-class FrontPortTable(DeviceComponentTable):
+class DeviceInterfaceTable(InterfaceTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ lag = tables.Column(
+ linkify=True,
+ verbose_name='LAG'
+ )
+ actions = ButtonsColumn(
+ model=Interface,
+ buttons=('edit', 'delete'),
+ prepend_template=INTERFACE_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = Interface
+ fields = (
+ 'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'description',
+ 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mtu', 'mode', 'description', 'ip_addresses', 'cable',
+ 'connection', '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'
)
+ rear_port = tables.Column(
+ linkify=True
+ )
tags = TagColumn(
url_name='dcim:frontport_list'
)
@@ -290,23 +457,77 @@ class FrontPortTable(DeviceComponentTable):
class Meta(DeviceComponentTable.Meta):
model = FrontPort
fields = (
- 'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'tags',
+ 'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable',
+ 'cable_peer', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description')
-class RearPortTable(DeviceComponentTable):
+class DeviceFrontPortTable(FrontPortTable):
+ name = tables.TemplateColumn(
+ template_code=' '
+ '{{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=FrontPort,
+ buttons=('edit', 'delete'),
+ prepend_template=FRONTPORT_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = FrontPort
+ fields = (
+ 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
+ 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
+ 'actions',
+ )
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
+class RearPortTable(DeviceComponentTable, CableTerminationTable):
tags = TagColumn(
url_name='dcim:rearport_list'
)
class Meta(DeviceComponentTable.Meta):
model = RearPort
- fields = ('pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'tags')
+ fields = ('pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
+class DeviceRearPortTable(RearPortTable):
+ name = tables.TemplateColumn(
+ template_code=' '
+ '{{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=RearPort,
+ buttons=('edit', 'delete'),
+ prepend_template=REARPORT_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = RearPort
+ fields = (
+ 'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'actions',
+ )
+ row_attrs = {
+ 'class': lambda record: record.cable.get_status_class() if record.cable else ''
+ }
+
+
class DeviceBayTable(DeviceComponentTable):
+ status = tables.TemplateColumn(
+ template_code=DEVICEBAY_STATUS
+ )
installed_device = tables.Column(
linkify=True
)
@@ -316,8 +537,29 @@ class DeviceBayTable(DeviceComponentTable):
class Meta(DeviceComponentTable.Meta):
model = DeviceBay
- fields = ('pk', 'device', 'name', 'label', 'installed_device', 'description', 'tags')
- default_columns = ('pk', 'device', 'name', 'label', 'installed_device', 'description')
+ fields = ('pk', 'device', 'name', 'label', 'status', 'installed_device', 'description', 'tags')
+ default_columns = ('pk', 'device', 'name', 'label', 'status', 'installed_device', 'description')
+
+
+class DeviceDeviceBayTable(DeviceBayTable):
+ name = tables.TemplateColumn(
+ template_code=' {{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=DeviceBay,
+ buttons=('edit', 'delete'),
+ prepend_template=DEVICEBAY_BUTTONS
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = DeviceBay
+ fields = (
+ 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'actions',
+ )
class InventoryItemTable(DeviceComponentTable):
@@ -339,6 +581,28 @@ class InventoryItemTable(DeviceComponentTable):
default_columns = ('pk', 'device', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag')
+class DeviceInventoryItemTable(InventoryItemTable):
+ name = tables.TemplateColumn(
+ template_code=''
+ '{{ value }} '
+ )
+ actions = ButtonsColumn(
+ model=InventoryItem,
+ buttons=('edit', 'delete')
+ )
+
+ class Meta(DeviceComponentTable.Meta):
+ model = InventoryItem
+ fields = (
+ 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
+ 'tags', 'actions',
+ )
+ default_columns = (
+ 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
+ 'actions',
+ )
+
+
#
# Virtual chassis
#
diff --git a/netbox/dcim/tables/power.py b/netbox/dcim/tables/power.py
index 8d90fb620..ae5c2a5c8 100644
--- a/netbox/dcim/tables/power.py
+++ b/netbox/dcim/tables/power.py
@@ -3,6 +3,7 @@ from django_tables2.utils import Accessor
from dcim.models import PowerFeed, PowerPanel
from utilities.tables import BaseTable, ChoiceFieldColumn, LinkedCountColumn, TagColumn, ToggleColumn
+from .devices import CableTerminationTable
from .template_code import POWERFEED_CABLE, POWERFEED_CABLETERMINATION
__all__ = (
@@ -41,7 +42,9 @@ class PowerPanelTable(BaseTable):
# Power feeds
#
-class PowerFeedTable(BaseTable):
+# We're not using PathEndpointTable for PowerFeed because power connections
+# cannot traverse pass-through ports.
+class PowerFeedTable(CableTerminationTable):
pk = ToggleColumn()
name = tables.LinkColumn()
power_panel = tables.Column(
@@ -55,15 +58,6 @@ class PowerFeedTable(BaseTable):
max_utilization = tables.TemplateColumn(
template_code="{{ value }}%"
)
- cable = tables.TemplateColumn(
- template_code=POWERFEED_CABLE,
- orderable=False
- )
- connection = tables.TemplateColumn(
- accessor='get_cable_peer',
- template_code=POWERFEED_CABLETERMINATION,
- orderable=False
- )
available_power = tables.Column(
verbose_name='Available power (VA)'
)
@@ -75,9 +69,9 @@ class PowerFeedTable(BaseTable):
model = PowerFeed
fields = (
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
- 'max_utilization', 'cable', 'connection', 'available_power', 'tags',
+ 'max_utilization', 'cable', 'cable_peer', 'connection', 'available_power', 'tags',
)
default_columns = (
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable',
- 'connection',
+ 'cable_peer',
)
diff --git a/netbox/dcim/tables/template_code.py b/netbox/dcim/tables/template_code.py
index b3840b48b..d0a316a3f 100644
--- a/netbox/dcim/tables/template_code.py
+++ b/netbox/dcim/tables/template_code.py
@@ -1,3 +1,13 @@
+CABLETERMINATION = """
+{% if value %}
+ {{ value.parent }}
+
+ {{ value }}
+{% else %}
+ —
+{% endif %}
+"""
+
CABLE_LENGTH = """
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% else %}—{% endif %}
"""
@@ -18,8 +28,18 @@ DEVICE_LINK = """
"""
+DEVICEBAY_STATUS = """
+{% if record.installed_device_id %}
+
+ {{ record.installed_device.get_status_display }}
+
+{% else %}
+ Vacant
+{% endif %}
+"""
+
INTERFACE_IPADDRESSES = """
-{% for ip in record.ip_addresses.unrestricted %}
+{% for ip in record.ip_addresses.all %}
{{ ip }}
{% endfor %}
"""
@@ -63,3 +83,149 @@ UTILIZATION_GRAPH = """
{% load helpers %}
{% utilization_graph value %}
"""
+
+#
+# Device component buttons
+#
+
+CONSOLEPORT_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+CONSOLESERVERPORT_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+POWERPORT_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+POWEROUTLET_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+{% endif %}
+"""
+
+INTERFACE_BUTTONS = """
+{% if perms.ipam.add_ipaddress %}
+
+
+
+{% endif %}
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif record.is_connectable and perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+FRONTPORT_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+REARPORT_BUTTONS = """
+{% if record.cable %}
+
+ {% include 'dcim/inc/cable_toggle_buttons.html' with cable=record.cable %}
+{% elif perms.dcim.add_cable %}
+
+
+
+
+
+
+{% endif %}
+"""
+
+DEVICEBAY_BUTTONS = """
+{% if perms.dcim.change_devicebay %}
+ {% if record.installed_device %}
+
+
+
+ {% else %}
+
+
+
+ {% endif %}
+{% endif %}
+"""
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
index 06fb7619f..fe652576b 100644
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -1019,6 +1019,9 @@ class DeviceView(ObjectView):
consoleports = ConsolePort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related(
'cable', '_path__destination',
)
+ consoleport_table = tables.DeviceConsolePortTable(consoleports, orderable=False)
+ if request.user.has_perm('dcim.change_consoleport') or request.user.has_perm('dcim.delete_consoleport'):
+ consoleport_table.columns.show('pk')
# Console server ports
consoleserverports = ConsoleServerPort.objects.restrict(request.user, 'view').filter(
@@ -1026,16 +1029,26 @@ class DeviceView(ObjectView):
).prefetch_related(
'cable', '_path__destination',
)
+ consoleserverport_table = tables.DeviceConsoleServerPortTable(consoleserverports, orderable=False)
+ if request.user.has_perm('dcim.change_consoleserverport') or \
+ request.user.has_perm('dcim.delete_consoleserverport'):
+ consoleserverport_table.columns.show('pk')
# Power ports
powerports = PowerPort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related(
'cable', '_path__destination',
)
+ powerport_table = tables.DevicePowerPortTable(powerports, orderable=False)
+ if request.user.has_perm('dcim.change_powerport') or request.user.has_perm('dcim.delete_powerport'):
+ powerport_table.columns.show('pk')
# Power outlets
poweroutlets = PowerOutlet.objects.restrict(request.user, 'view').filter(device=device).prefetch_related(
'cable', 'power_port', '_path__destination',
)
+ poweroutlet_table = tables.DevicePowerOutletTable(poweroutlets, orderable=False)
+ if request.user.has_perm('dcim.change_poweroutlet') or request.user.has_perm('dcim.delete_poweroutlet'):
+ poweroutlet_table.columns.show('pk')
# Interfaces
interfaces = device.vc_interfaces.restrict(request.user, 'view').prefetch_related(
@@ -1043,24 +1056,39 @@ 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(
'rear_port', 'cable',
)
+ frontport_table = tables.DeviceFrontPortTable(frontports, orderable=False)
+ if request.user.has_perm('dcim.change_frontport') or request.user.has_perm('dcim.delete_frontport'):
+ frontport_table.columns.show('pk')
# Rear ports
rearports = RearPort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related('cable')
+ rearport_table = tables.DeviceRearPortTable(rearports, orderable=False)
+ if request.user.has_perm('dcim.change_rearport') or request.user.has_perm('dcim.delete_rearport'):
+ rearport_table.columns.show('pk')
# Device bays
devicebays = DeviceBay.objects.restrict(request.user, 'view').filter(device=device).prefetch_related(
'installed_device__device_type__manufacturer',
)
+ devicebay_table = tables.DeviceDeviceBayTable(devicebays, orderable=False)
+ if request.user.has_perm('dcim.change_devicebay') or request.user.has_perm('dcim.delete_devicebay'):
+ devicebay_table.columns.show('pk')
# Inventory items
inventoryitems = InventoryItem.objects.restrict(request.user, 'view').filter(
device=device
).prefetch_related('manufacturer')
+ inventoryitem_table = tables.DeviceInventoryItemTable(inventoryitems, orderable=False)
+ if request.user.has_perm('dcim.change_inventoryitem') or request.user.has_perm('dcim.delete_inventoryitem'):
+ devicebay_table.columns.show('pk')
# Services
services = Service.objects.restrict(request.user, 'view').filter(device=device)
@@ -1079,15 +1107,15 @@ class DeviceView(ObjectView):
return render(request, 'dcim/device.html', {
'device': device,
- 'consoleports': consoleports,
- 'consoleserverports': consoleserverports,
- 'powerports': powerports,
- 'poweroutlets': poweroutlets,
- 'interfaces': interfaces,
- 'frontports': frontports,
- 'rearports': rearports,
- 'devicebays': devicebays,
- 'inventoryitems': inventoryitems,
+ 'consoleport_table': consoleport_table,
+ 'consoleserverport_table': consoleserverport_table,
+ 'powerport_table': powerport_table,
+ 'poweroutlet_table': poweroutlet_table,
+ 'interface_table': interface_table,
+ 'frontport_table': frontport_table,
+ 'rearport_table': rearport_table,
+ 'devicebay_table': devicebay_table,
+ 'inventoryitem_table': inventoryitem_table,
'services': services,
'secrets': secrets,
'vc_members': vc_members,
diff --git a/netbox/project-static/js/interface_toggles.js b/netbox/project-static/js/interface_toggles.js
index df8ac064b..bf205b92a 100644
--- a/netbox/project-static/js/interface_toggles.js
+++ b/netbox/project-static/js/interface_toggles.js
@@ -1,16 +1,3 @@
-// Toggle the display of IP addresses under interfaces
-$('button.toggle-ips').click(function() {
- var selected = $(this).attr('selected');
- if (selected) {
- $('#interfaces_table tr.interface:visible + tr.ipaddresses').hide();
- } else {
- $('#interfaces_table tr.interface:visible + tr.ipaddresses').show();
- }
- $(this).attr('selected', !selected);
- $(this).children('span').toggleClass('glyphicon-check glyphicon-unchecked');
- return false;
-});
-
// Inteface filtering
$('input.interface-filter').on('input', function() {
var filter = new RegExp(this.value);
diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html
index c06f86bf0..7253bdcae 100644
--- a/netbox/templates/dcim/device.html
+++ b/netbox/templates/dcim/device.html
@@ -122,31 +122,31 @@
Details
- Interfaces {% badge interfaces|length %}
+ Interfaces {% badge interface_table.rows|length %}
- Front Ports {% badge frontports|length %}
+ Front Ports {% badge frontport_table.rows|length %}
- Rear Ports {% badge rearports|length %}
+ Rear Ports {% badge rearport_table.rows|length %}
- Console Ports {% badge consoleports|length %}
+ Console Ports {% badge consoleport_table.rows|length %}
- Console Server Ports {% badge consoleserverports|length %}
+ Console Server Ports {% badge consoleserverport_table.rows|length %}
- Power Ports {% badge powerports|length %}
+ Power Ports {% badge powerport_table.rows|length %}
- Power Outlets {% badge poweroutlets|length %}
+ Power Outlets {% badge poweroutlet_table.rows|length %}
- Device Bays {% badge devicebays|length %}
+ Device Bays {% badge devicebay_table.rows|length %}
- Inventory {% badge inventoryitems|length %}
+ Inventory {% badge inventoryitem_table.rows|length %}
@@ -485,38 +485,11 @@
Interfaces
-
-
- Show IPs
-
-
-
+ {% include 'responsive_table.html' with table=interface_table %}
-
{% endif %}
+
@@ -555,30 +528,9 @@
Front Ports
-
+ {% include 'responsive_table.html' with table=frontport_table %}
-
{% endif %}
+
@@ -613,29 +565,9 @@
Rear Ports
-
+ {% include 'responsive_table.html' with table=rearport_table %}
-
{% endif %}
+
@@ -670,27 +602,9 @@
Console Ports
-
+ {% include 'responsive_table.html' with table=consoleport_table %}
{% endif %}
+
@@ -724,29 +639,9 @@
Console Server Ports
-
+ {% include 'responsive_table.html' with table=consoleserverport_table %}
-
{% endif %}
+
@@ -781,27 +676,9 @@
Power Ports
-
+ {% include 'responsive_table.html' with table=powerport_table %}
@@ -892,36 +749,14 @@
Device Bays
-
+ {% include 'responsive_table.html' with table=devicebay_table %}
-
{% endif %}
+
@@ -945,28 +780,7 @@
Inventory Items
-
+ {% include 'responsive_table.html' with table=inventoryitem_table %}
{% endif %}
+
diff --git a/netbox/templates/dcim/inc/consoleport.html b/netbox/templates/dcim/inc/consoleport.html
deleted file mode 100644
index ace09cfe2..000000000
--- a/netbox/templates/dcim/inc/consoleport.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
- {# Checkbox #}
- {% if perms.dcim.change_consoleport or perms.dcim.delete_consoleport %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ cp }}
-
-
- {# Type #}
-
- {% if cp.type %}{{ cp.get_type_display }}{% else %}—{% endif %}
-
-
- {# Description #}
-
- {{ cp.description }}
-
-
- {# Cable #}
- {% if cp.cable %}
-
- {{ cp.cable }}
-
-
-
-
- {% include 'dcim/inc/cabletermination.html' with termination=cp.get_cable_peer %}
- {% else %}
-
- Not connected
-
- {% endif %}
-
- {# Connection #}
- {% include 'dcim/inc/endpoint_connection.html' with path=cp.path %}
-
- {# Actions #}
-
- {% if cp.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=cp.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
-
-
-
- {% endif %}
- {% if perms.dcim.change_consoleport %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_consoleport %}
- {% if cp.connected_endpoint %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/consoleserverport.html b/netbox/templates/dcim/inc/consoleserverport.html
deleted file mode 100644
index 025b0bf02..000000000
--- a/netbox/templates/dcim/inc/consoleserverport.html
+++ /dev/null
@@ -1,79 +0,0 @@
-{% load helpers %}
-
-
-
- {# Checkbox #}
- {% if perms.dcim.change_consoleserverport or perms.dcim.delete_consoleserverport %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ csp }}
-
-
- {# Type #}
-
- {% if csp.type %}{{ csp.get_type_display }}{% else %}—{% endif %}
-
-
- {# Description #}
-
- {{ csp.description|placeholder }}
-
-
- {# Cable #}
- {% if csp.cable %}
-
- {{ csp.cable }}
-
-
-
-
- {% include 'dcim/inc/cabletermination.html' with termination=csp.get_cable_peer %}
- {% else %}
-
- Not connected
-
- {% endif %}
-
- {# Connection #}
- {% include 'dcim/inc/endpoint_connection.html' with path=csp.path %}
-
- {# Actions #}
-
- {% if csp.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=csp.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
-
-
-
- {% endif %}
- {% if perms.dcim.change_consoleserverport %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_consoleserverport %}
- {% if csp.connected_endpoint %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/devicebay.html b/netbox/templates/dcim/inc/devicebay.html
deleted file mode 100644
index bde7b8641..000000000
--- a/netbox/templates/dcim/inc/devicebay.html
+++ /dev/null
@@ -1,71 +0,0 @@
-{% load helpers %}
-
-
- {% if perms.dcim.change_devicebay or perms.dcim.delete_devicebay %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ devicebay.name }}
-
-
- {# Status #}
-
- {% if devicebay.installed_device %}
-
- {{ devicebay.installed_device.get_status_display }}
-
- {% else %}
- Vacant
- {% endif %}
-
-
- {# Description #}
-
- {{ devicebay.description|placeholder }}
-
-
- {# Installed device #}
- {% if devicebay.installed_device %}
-
- {{ devicebay.installed_device }}
-
-
- {{ devicebay.installed_device.device_type.display_name }}
-
- {% else %}
-
- {% endif %}
-
-
- {% if perms.dcim.change_devicebay %}
- {% if devicebay.installed_device %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_devicebay %}
- {% if devicebay.installed_device %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/frontport.html b/netbox/templates/dcim/inc/frontport.html
deleted file mode 100644
index 91374cb1e..000000000
--- a/netbox/templates/dcim/inc/frontport.html
+++ /dev/null
@@ -1,72 +0,0 @@
-{% load helpers %}
-
-
- {# Checkbox #}
- {% if perms.dcim.change_frontport or perms.dcim.delete_frontport %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ frontport }}
-
-
- {# Type #}
- {{ frontport.get_type_display }}
-
- {# Rear port #}
- {{ frontport.rear_port }}
- {{ frontport.rear_port_position }}
-
- {# Description #}
- {{ frontport.description|placeholder }}
-
- {# Cable #}
- {% if frontport.cable %}
-
- {{ frontport.cable }}
-
-
-
-
- {% include 'dcim/inc/cabletermination.html' with termination=frontport.get_cable_peer %}
- {% else %}
-
- Not connected
-
- {% endif %}
-
- {# Actions #}
-
- {% if frontport.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=frontport.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
-
-
-
- {% endif %}
- {% if perms.dcim.change_frontport %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_frontport %}
-
-
-
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/interface.html b/netbox/templates/dcim/inc/interface.html
deleted file mode 100644
index efaed7ecf..000000000
--- a/netbox/templates/dcim/inc/interface.html
+++ /dev/null
@@ -1,200 +0,0 @@
-{% load helpers %}
-
-
- {# Checkbox #}
- {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
-
-
-
- {% endif %}
-
- {# Icon and name #}
-
-
-
- {{ iface }}
-
- {% if iface.mac_address %}
- {{ iface.mac_address }}
- {% endif %}
-
-
- {# LAG #}
-
- {% if iface.lag %}
- {{ iface.lag }}
- {% endif %}
-
-
- {# Description/tags #}
-
- {% if iface.description %}
- {{ iface.description }}
- {% endif %}
- {% for tag in iface.tags.all %}
- {% tag tag %}
- {% empty %}
- {% if not iface.description %}—{% endif %}
- {% endfor %}
-
-
- {# MTU #}
- {{ iface.mtu|default:"—" }}
-
- {# 802.1Q mode #}
- {{ iface.get_mode_display|default:"—" }}
-
- {# Cable #}
- {% if iface.cable %}
-
- {{ iface.cable }}
-
-
-
-
- {% include 'dcim/inc/cabletermination.html' with termination=iface.get_cable_peer %}
- {% else %}
-
- Not connected
-
- {% endif %}
-
- {# Connection or type #}
- {% if iface.is_lag %}
-
- LAG interface
-
- {% for member in iface.member_interfaces.all %}
- {{ member }} {% if not forloop.last %}, {% endif %}
- {% empty %}
- No members
- {% endfor %}
-
-
- {% elif iface.is_virtual %}
- Virtual interface
- {% elif iface.is_wireless %}
- Wireless interface
- {% else %}
- {% include 'dcim/inc/endpoint_connection.html' with path=iface.path %}
- {% endif %}
-
- {# Buttons #}
-
- {% if perms.ipam.add_ipaddress %}
-
-
-
- {% 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 %}
-
-
-
-
-
-
- {% endif %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_interface %}
- {% if iface.connection or iface.circuit_termination %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
-
-{% with ipaddresses=iface.ip_addresses.all %}
- {% if ipaddresses %}
-
- {# Placeholder #}
- {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
-
- {% endif %}
-
- {# IP addresses table #}
-
-
-
-
- IP Address
- Status/Role
- VRF
- Description
-
-
-
- {% for ip in iface.ip_addresses.all %}
-
-
- {# IP address #}
-
- {{ ip }}
-
-
- {# Primary/status/role #}
-
- {% if device.primary_ip4 == ip or device.primary_ip6 == ip %}
- Primary
- {% endif %}
- {{ ip.get_status_display }}
- {% if ip.role %}
- {{ ip.get_role_display }}
- {% endif %}
-
-
- {# VRF #}
-
- {% if ip.vrf %}
- {{ ip.vrf.name }}
- {% else %}
- Global
- {% endif %}
-
-
- {# Description #}
-
- {% if ip.description %}
- {{ ip.description }}
- {% else %}
- —
- {% endif %}
-
-
- {# Buttons #}
-
- {% if perms.ipam.change_ipaddress %}
-
-
-
- {% endif %}
- {% if perms.ipam.delete_ipaddress %}
-
-
-
- {% endif %}
-
-
-
- {% endfor %}
-
-
-
- {% endif %}
-{% endwith %}
diff --git a/netbox/templates/dcim/inc/inventoryitem.html b/netbox/templates/dcim/inc/inventoryitem.html
deleted file mode 100644
index f7309fa59..000000000
--- a/netbox/templates/dcim/inc/inventoryitem.html
+++ /dev/null
@@ -1,40 +0,0 @@
-{% load helpers %}
-
-
- {# Checkbox #}
- {% if perms.dcim.change_inventoryitem or perms.dcim.delete_inventoryitem %}
-
-
-
- {% endif %}
-
-
- {{ item }}
-
-
- {% if item.manufacturer %}
- {{ item.manufacturer }}
- {% else %}
- —
- {% endif %}
-
- {{ item.part_id|placeholder }}
- {{ item.serial|placeholder }}
- {{ item.asset_tag|placeholder }}
-
- {% if item.discovered %}
-
- {% else %}
- —
- {% endif %}
-
- {{ item.description|placeholder }}
-
- {% if perms.dcim.change_inventoryitem %}
-
- {% endif %}
- {% if perms.dcim.delete_inventoryitem %}
-
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/poweroutlet.html b/netbox/templates/dcim/inc/poweroutlet.html
deleted file mode 100644
index a6a0dd03e..000000000
--- a/netbox/templates/dcim/inc/poweroutlet.html
+++ /dev/null
@@ -1,93 +0,0 @@
-{% load helpers %}
-
-
-
- {# Checkbox #}
- {% if perms.dcim.change_poweroutlet or perms.dcim.delete_poweroutlet %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ po }}
-
-
- {# Type #}
-
- {{ po.get_type_display }}
-
-
- {# Input/leg #}
-
- {% if po.power_port %}
- {{ po.power_port }}{% if po.feed_leg %} / {{ po.get_feed_leg_display }}{% endif %}
- {% elif po.feed_leg %}
- {{ po.get_feed_leg_display }}
- {% else %}
- None
- {% endif %}
-
-
- {# Description #}
-
- {{ po.description|placeholder }}
-
-
- {# Cable #}
- {% if po.cable %}
-
- {{ po.cable }}
-
-
-
-
- {% else %}
- Not connected
- {% endif %}
-
- {# Connection #}
- {% with path=po.path %}
- {% include 'dcim/inc/endpoint_connection.html' %}
-
- {% if paths|length == 1 %}
- {% with pp=paths.0.destination %}
- {% if pp.allocated_draw %}
- {{ pp.allocated_draw }}W{% if pp.maximum_draw %} ({{ pp.maximum_draw }}W max){% endif %}
- {% elif pp.maximum_draw %}
- {{ pp.maximum_draw }}W
- {% endif %}
- {% endwith %}
- {% endif %}
-
- {% endwith %}
-
- {# Actions #}
-
- {% if po.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=po.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
- {% endif %}
- {% if perms.dcim.change_poweroutlet %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_poweroutlet %}
- {% if po.connected_endpoint %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/powerport.html b/netbox/templates/dcim/inc/powerport.html
deleted file mode 100644
index 125bc5445..000000000
--- a/netbox/templates/dcim/inc/powerport.html
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
- {# Checkbox #}
- {% if perms.dcim.change_powerport or perms.dcim.delete_powerport %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ pp }}
-
-
- {# Type #}
-
- {{ pp.get_type_display }}
-
-
- {# Current draw #}
-
- {% if pp.allocated_draw %}
- {{ pp.allocated_draw }}W{% if pp.maximum_draw %} ({{ pp.maximum_draw }}W max){% endif %}
- {% elif pp.maximum_draw %}
- {{ pp.maximum_draw }}W
- {% endif %}
-
-
- {# Description #}
-
- {{ pp.description }}
-
-
- {# Cable #}
- {% if pp.cable %}
-
- {{ pp.cable }}
-
-
-
-
- {% else %}
- Not connected
- {% endif %}
-
- {# Connection #}
- {% include 'dcim/inc/endpoint_connection.html' with path=pp.path %}
-
- {# Actions #}
-
- {% if pp.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=pp.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
-
-
-
- {% endif %}
- {% if perms.dcim.change_powerport %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_powerport %}
- {% if pp.connected_endpoint %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
- {% endif %}
-
-
diff --git a/netbox/templates/dcim/inc/rearport.html b/netbox/templates/dcim/inc/rearport.html
deleted file mode 100644
index fd5ee620c..000000000
--- a/netbox/templates/dcim/inc/rearport.html
+++ /dev/null
@@ -1,69 +0,0 @@
-{% load helpers %}
-
-
- {# Checkbox #}
- {% if perms.dcim.change_rearport or perms.dcim.delete_rearport %}
-
-
-
- {% endif %}
-
- {# Name #}
-
-
- {{ rearport }}
-
-
- {# Type #}
- {{ rearport.get_type_display }}
-
- {# Positions #}
- {{ rearport.positions }}
-
- {# Description #}
- {{ rearport.description|placeholder }}
-
- {# Cable #}
- {% if rearport.cable %}
-
- {{ rearport.cable }}
-
-
-
-
- {% include 'dcim/inc/cabletermination.html' with termination=rearport.get_cable_peer %}
- {% else %}
-
- Not connected
-
- {% endif %}
-
- {# Actions #}
-
- {% if rearport.cable %}
- {% include 'dcim/inc/cable_toggle_buttons.html' with cable=rearport.cable %}
- {% elif perms.dcim.add_cable %}
-
-
-
-
-
-
- {% endif %}
- {% if perms.dcim.change_rearport %}
-
-
-
- {% endif %}
- {% if perms.dcim.delete_rearport %}
-
-
-
- {% endif %}
-
-
diff --git a/netbox/templates/virtualization/inc/vminterface.html b/netbox/templates/virtualization/inc/vminterface.html
deleted file mode 100644
index 93efafb5a..000000000
--- a/netbox/templates/virtualization/inc/vminterface.html
+++ /dev/null
@@ -1,136 +0,0 @@
-{% load helpers %}
-
-
- {# Checkbox #}
- {% if perms.virtualization.change_vminterface or perms.virtualization.delete_vminterface %}
-
-
-
- {% endif %}
-
- {# Name #}
-
- {{ iface }}
-
-
- {# MAC address #}
-
- {{ iface.mac_address|default:"—" }}
-
-
- {# MTU #}
- {{ iface.mtu|default:"—" }}
-
- {# 802.1Q mode #}
- {{ iface.get_mode_display|default:"—" }}
-
- {# Description/tags #}
-
- {% if iface.description %}
- {{ iface.description }}
- {% endif %}
- {% for tag in iface.tags.all %}
- {% tag tag %}
- {% empty %}
- {% if not iface.description %}—{% endif %}
- {% endfor %}
-
-
- {# Buttons #}
-
- {% if perms.ipam.add_ipaddress %}
-
-
-
- {% endif %}
- {% if perms.virtualization.change_vminterface %}
-
-
-
- {% endif %}
- {% if perms.virtualization.delete_vminterface %}
-
-
-
- {% endif %}
-
-
-
-{% with ipaddresses=iface.ip_addresses.all %}
- {% if ipaddresses %}
-
- {# Placeholder #}
- {% if perms.virtualization.change_vminterface or perms.virtualization.delete_vminterface %}
-
- {% endif %}
-
- {# IP addresses table #}
-
-
-
-
- IP Address
- Status/Role
- VRF
- Description
-
-
-
- {% for ip in iface.ip_addresses.all %}
-
-
- {# IP address #}
-
- {{ ip }}
-
-
- {# Primary/status/role #}
-
- {% if virtualmachine.primary_ip4 == ip or virtualmachine.primary_ip6 == ip %}
- Primary
- {% endif %}
- {{ ip.get_status_display }}
- {% if ip.role %}
- {{ ip.get_role_display }}
- {% endif %}
-
-
- {# VRF #}
-
- {% if ip.vrf %}
- {{ ip.vrf.name }}
- {% else %}
- Global
- {% endif %}
-
-
- {# Description #}
-
- {% if ip.description %}
- {{ ip.description }}
- {% else %}
- —
- {% endif %}
-
-
- {# Buttons #}
-
- {% if perms.ipam.change_ipaddress %}
-
-
-
- {% endif %}
- {% if perms.ipam.delete_ipaddress %}
-
-
-
- {% endif %}
-
-
-
- {% endfor %}
-
-
-
- {% endif %}
-{% endwith %}
diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html
index 7eabcf504..a2213aee1 100644
--- a/netbox/templates/virtualization/virtualmachine.html
+++ b/netbox/templates/virtualization/virtualmachine.html
@@ -276,39 +276,11 @@
Interfaces
-
-
- Show IPs
-
-
-
+ {% include 'responsive_table.html' with table=vminterface_table %}
{% if perms.virtualization.add_vminterface or perms.virtualization.delete_vminterface %}