diff --git a/netbox/dcim/ui/panels.py b/netbox/dcim/ui/panels.py
index 4d86d7659..72b82aad0 100644
--- a/netbox/dcim/ui/panels.py
+++ b/netbox/dcim/ui/panels.py
@@ -470,3 +470,106 @@ class PowerUtilizationPanel(panels.ObjectPanel):
if not obj.powerports.exists() or not obj.poweroutlets.exists():
return ''
return super().render(context)
+
+
+class InterfacePanel(panels.ObjectAttributesPanel):
+ device = attrs.RelatedObjectAttr('device', linkify=True)
+ module = attrs.RelatedObjectAttr('module', linkify=True)
+ name = attrs.TextAttr('name')
+ label = attrs.TextAttr('label')
+ type = attrs.ChoiceAttr('type')
+ speed = attrs.TemplatedAttr('speed', template_name='dcim/interface/attrs/speed.html', label=_('Speed'))
+ duplex = attrs.ChoiceAttr('duplex')
+ mtu = attrs.TextAttr('mtu', label=_('MTU'))
+ enabled = attrs.BooleanAttr('enabled')
+ mgmt_only = attrs.BooleanAttr('mgmt_only', label=_('Management only'))
+ description = attrs.TextAttr('description')
+ poe_mode = attrs.ChoiceAttr('poe_mode', label=_('PoE mode'))
+ poe_type = attrs.ChoiceAttr('poe_type', label=_('PoE type'))
+ mode = attrs.ChoiceAttr('mode', label=_('802.1Q mode'))
+ qinq_svlan = attrs.RelatedObjectAttr('qinq_svlan', linkify=True, label=_('Q-in-Q SVLAN'))
+ untagged_vlan = attrs.RelatedObjectAttr('untagged_vlan', linkify=True, label=_('Untagged VLAN'))
+ tx_power = attrs.TextAttr('tx_power', label=_('Transmit power (dBm)'))
+ tunnel = attrs.RelatedObjectAttr('tunnel_termination.tunnel', linkify=True, label=_('Tunnel'))
+ l2vpn = attrs.RelatedObjectAttr('l2vpn_termination.l2vpn', linkify=True, label=_('L2VPN'))
+
+
+class RelatedInterfacesPanel(panels.ObjectAttributesPanel):
+ title = _('Related Interfaces')
+
+ parent = attrs.RelatedObjectAttr('parent', linkify=True)
+ bridge = attrs.RelatedObjectAttr('bridge', linkify=True)
+ lag = attrs.RelatedObjectAttr('lag', linkify=True, label=_('LAG'))
+
+
+class InterfaceAddressingPanel(panels.ObjectAttributesPanel):
+ title = _('Addressing')
+
+ mac_address = attrs.TemplatedAttr(
+ 'primary_mac_address',
+ template_name='dcim/interface/attrs/mac_address.html',
+ label=_('MAC address'),
+ )
+ wwn = attrs.TextAttr('wwn', style='font-monospace', label=_('WWN'))
+ vrf = attrs.RelatedObjectAttr('vrf', linkify=True, label=_('VRF'))
+ vlan_translation = attrs.RelatedObjectAttr('vlan_translation_policy', linkify=True, label=_('VLAN translation'))
+
+
+class InterfaceConnectionPanel(panels.ObjectPanel):
+ """
+ A connection panel for interfaces, which handles cable, wireless link, and virtual circuit cases.
+ """
+ template_name = 'dcim/panels/interface_connection.html'
+ title = _('Connection')
+
+ def render(self, context):
+ obj = context.get('object')
+ if obj and obj.is_virtual:
+ return ''
+ ctx = self.get_context(context)
+ return render_to_string(self.template_name, ctx, request=ctx.get('request'))
+
+
+class VirtualCircuitPanel(panels.ObjectPanel):
+ """
+ A panel which displays virtual circuit information for a virtual interface.
+ """
+ template_name = 'dcim/panels/interface_virtual_circuit.html'
+ title = _('Virtual Circuit')
+
+ def render(self, context):
+ obj = context.get('object')
+ if not obj or not obj.is_virtual or not obj.virtual_circuit_termination:
+ return ''
+ ctx = self.get_context(context)
+ return render_to_string(self.template_name, ctx, request=ctx.get('request'))
+
+
+class InterfaceWirelessPanel(panels.ObjectPanel):
+ """
+ A panel which displays wireless RF attributes for an interface, comparing local and peer values.
+ """
+ template_name = 'dcim/panels/interface_wireless.html'
+ title = _('Wireless')
+
+ def render(self, context):
+ obj = context.get('object')
+ if not obj or not obj.is_wireless:
+ return ''
+ ctx = self.get_context(context)
+ return render_to_string(self.template_name, ctx, request=ctx.get('request'))
+
+
+class WirelessLANsPanel(panels.ObjectPanel):
+ """
+ A panel which lists the wireless LANs associated with an interface.
+ """
+ template_name = 'dcim/panels/interface_wireless_lans.html'
+ title = _('Wireless LANs')
+
+ def render(self, context):
+ obj = context.get('object')
+ if not obj or not obj.is_wireless:
+ return ''
+ ctx = self.get_context(context)
+ return render_to_string(self.template_name, ctx, request=ctx.get('request'))
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
index 4d1a2e4f2..047b3c7f3 100644
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -17,10 +17,12 @@ from extras.ui.panels import CustomFieldsPanel, ImageAttachmentsPanel, TagsPanel
from extras.views import ObjectConfigContextView, ObjectRenderConfigView
from ipam.models import ASN, VLAN, IPAddress, Prefix, VLANGroup
from ipam.tables import VLANTranslationRuleTable
+from ipam.ui.panels import FHRPGroupAssignmentsPanel
from netbox.object_actions import *
from netbox.ui import actions, layout
from netbox.ui.panels import (
CommentsPanel,
+ ContextTablePanel,
JSONPanel,
NestedGroupObjectPanel,
ObjectsTablePanel,
@@ -3265,6 +3267,45 @@ class InterfaceListView(generic.ObjectListView):
@register_model_view(Interface)
class InterfaceView(generic.ObjectView):
queryset = Interface.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.InterfacePanel(),
+ panels.RelatedInterfacesPanel(),
+ CustomFieldsPanel(),
+ TagsPanel(),
+ ],
+ right_panels=[
+ ContextTablePanel('vdc_table', title=_('Virtual Device Contexts')),
+ panels.InterfaceAddressingPanel(),
+ panels.VirtualCircuitPanel(),
+ panels.InterfaceConnectionPanel(),
+ panels.InterfaceWirelessPanel(),
+ panels.WirelessLANsPanel(),
+ FHRPGroupAssignmentsPanel(),
+ panels.InventoryItemsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ model='ipam.IPAddress',
+ filters={'interface_id': lambda ctx: ctx['object'].pk},
+ title=_('IP Addresses'),
+ ),
+ ObjectsTablePanel(
+ model='dcim.MACAddress',
+ filters={'interface_id': lambda ctx: ctx['object'].pk},
+ title=_('MAC Addresses'),
+ ),
+ ObjectsTablePanel(
+ model='ipam.VLAN',
+ filters={'interface_id': lambda ctx: ctx['object'].pk},
+ title=_('VLANs'),
+ ),
+ ContextTablePanel('lag_interfaces_table', title=_('LAG Members')),
+ ContextTablePanel('vlan_translation_table', title=_('VLAN Translation')),
+ ContextTablePanel('bridge_interfaces_table', title=_('Bridged Interfaces')),
+ ContextTablePanel('child_interfaces_table', title=_('Child Interfaces')),
+ ],
+ )
def get_extra_context(self, request, instance):
# Get assigned VDCs
@@ -3279,30 +3320,29 @@ class InterfaceView(generic.ObjectView):
vdc_table.configure(request)
# Get bridge interfaces
- bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance)
bridge_interfaces_table = tables.InterfaceTable(
- bridge_interfaces,
+ Interface.objects.restrict(request.user, 'view').filter(bridge=instance),
exclude=('device', 'parent'),
orderable=False
)
bridge_interfaces_table.configure(request)
# Get child interfaces
- child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance)
child_interfaces_table = tables.InterfaceTable(
- child_interfaces,
+ Interface.objects.restrict(request.user, 'view').filter(parent=instance),
exclude=('device', 'parent'),
orderable=False
)
child_interfaces_table.configure(request)
- # Get LAG interfaces
- lag_interfaces = Interface.objects.restrict(request.user, 'view').filter(lag=instance)
- lag_interfaces_table = tables.InterfaceLAGMemberTable(
- lag_interfaces,
- orderable=False
- )
- lag_interfaces_table.configure(request)
+ # Get LAG members (only for LAG interfaces)
+ lag_interfaces_table = None
+ if instance.is_lag:
+ lag_interfaces_table = tables.InterfaceLAGMemberTable(
+ Interface.objects.restrict(request.user, 'view').filter(lag=instance),
+ orderable=False
+ )
+ lag_interfaces_table.configure(request)
# Get VLAN translation rules
vlan_translation_table = None
@@ -3315,7 +3355,6 @@ class InterfaceView(generic.ObjectView):
return {
'vdc_table': vdc_table,
- 'bridge_interfaces': bridge_interfaces,
'bridge_interfaces_table': bridge_interfaces_table,
'child_interfaces_table': child_interfaces_table,
'lag_interfaces_table': lag_interfaces_table,
diff --git a/netbox/templates/dcim/interface.html b/netbox/templates/dcim/interface.html
index 34e941ec9..b8214337f 100644
--- a/netbox/templates/dcim/interface.html
+++ b/netbox/templates/dcim/interface.html
@@ -1,7 +1,4 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load render_table from django_tables2 %}
{% load i18n %}
{% block breadcrumbs %}
@@ -19,436 +16,3 @@
{% endif %}
{{ block.super }}
{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Device" %} |
- {{ object.device|linkify }} |
-
-
- | {% trans "Module" %} |
- {{ object.module|linkify|placeholder }} |
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Label" %} |
- {{ object.label|placeholder }} |
-
-
- | {% trans "Type" %} |
- {{ object.get_type_display }} |
-
-
- | {% trans "Speed/Duplex" %} |
-
- {{ object.speed|humanize_speed|placeholder }} /
- {{ object.get_duplex_display|placeholder }}
- |
-
-
- | {% trans "MTU" %} |
- {{ object.mtu|placeholder }} |
-
-
- | {% trans "Enabled" %} |
- {% checkmark object.enabled %} |
-
-
- | {% trans "Management Only" %} |
- {% checkmark object.mgmt_only %} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "PoE Mode" %} |
- {{ object.get_poe_mode_display|placeholder }} |
-
-
- | {% trans "PoE Type" %} |
- {{ object.get_poe_type_display|placeholder }} |
-
-
- | {% trans "802.1Q Mode" %} |
- {{ object.get_mode_display|placeholder }} |
-
- {% if object.mode == 'q-in-q' %}
-
- | {% trans "Q-in-Q SVLAN" %} |
- {{ object.qinq_svlan|linkify|placeholder }} |
-
- {% elif object.mode %}
-
- | {% trans "Untagged VLAN" %} |
- {{ object.untagged_vlan|linkify|placeholder }} |
-
- {% endif %}
-
- | {% trans "Transmit power (dBm)" %} |
- {{ object.tx_power|placeholder }} |
-
-
- | {% trans "Tunnel" %} |
- {{ object.tunnel_termination.tunnel|linkify|placeholder }} |
-
-
- | {% trans "L2VPN" %} |
- {{ object.l2vpn_termination.l2vpn|linkify|placeholder }} |
-
-
-
-
-
-
-
- | {% trans "Parent" %} |
- {{ object.parent|linkify|placeholder }} |
-
-
- | {% trans "Bridge" %} |
- {{ object.bridge|linkify|placeholder }} |
-
-
- | {% trans "Bridged Interfaces" %} |
-
- {% if bridge_interfaces %}
- {% for interface in bridge_interfaces %}
- {{ interface|linkify }}
- {% if not forloop.last %} {% endif %}
- {% endfor %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
-
-
- | {% trans "LAG" %} |
- {{ object.lag|linkify|placeholder }} |
-
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/tags.html' %}
- {% plugin_left_page object %}
-
-
- {% include 'inc/panel_table.html' with table=vdc_table heading="Virtual Device Contexts" %}
-
-
-
-
- | {% trans "MAC Address" %} |
-
- {% if object.primary_mac_address %}
- {{ object.primary_mac_address|linkify }}
- {% trans "Primary" %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
-
-
- | {% trans "WWN" %} |
-
- {% if object.wwn %}
- {{ object.wwn }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
-
-
- | {% trans "VRF" %} |
- {{ object.vrf|linkify|placeholder }} |
-
-
- | {% trans "VLAN Translation" %} |
- {{ object.vlan_translation_policy|linkify|placeholder }} |
-
-
-
- {% if object.is_virtual and object.virtual_circuit_termination %}
-
-
-
-
- | {% trans "Provider" %} |
- {{ object.virtual_circuit_termination.virtual_circuit.provider|linkify }} |
-
-
- | {% trans "Provider Network" %} |
- {{ object.virtual_circuit_termination.virtual_circuit.provider_network|linkify }} |
-
-
- | {% trans "Circuit ID" %} |
- {{ object.virtual_circuit_termination.virtual_circuit|linkify }} |
-
-
- | {% trans "Role" %} |
- {{ object.virtual_circuit_termination.get_role_display }} |
-
-
- | {% trans "Connections" %} |
-
- {% for termination in object.virtual_circuit_termination.peer_terminations %}
- {{ termination.interface.parent_object }}
-
- {{ termination.interface }}
- ({{ termination.get_role_display }})
- {% if not forloop.last %} {% endif %}
- {% endfor %}
- |
-
-
-
- {% elif not object.is_virtual %}
-
-
- {% if object.mark_connected %}
-
-
- {% trans "Marked as Connected" %}
-
- {% elif object.cable %}
- {% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:interface_trace' %}
- {% elif object.wireless_link %}
-
-
- | {% trans "Wireless Link" %} |
-
- {{ object.wireless_link|linkify }}
-
-
-
- |
-
- {% with peer_interface=object.link_peers.0 %}
-
- | {% trans "Device" %} |
- {{ peer_interface.device|linkify }} |
-
-
- | {% trans "Name" %} |
- {{ peer_interface|linkify }} |
-
-
- | {% trans "Type" %} |
- {{ peer_interface.get_type_display }} |
-
- {% endwith %}
-
- {% else %}
-
- {% trans "Not Connected" %}
- {% if object.is_wired and perms.dcim.add_cable %}
-
-
-
-
- {% elif object.is_wireless and perms.wireless.add_wirelesslink %}
-
- {% endif %}
-
- {% endif %}
-
- {% endif %}
- {% if object.is_wireless %}
-
-
- {% with peer=object.connected_endpoints.0 %}
-
-
-
- |
- {% trans "Local" %} |
- {% if peer %}
- {% trans "Peer" %} |
- {% endif %}
-
-
-
- | {% trans "Role" %} |
- {{ object.get_rf_role_display|placeholder }} |
- {% if peer %}
- {{ peer.get_rf_role_display|placeholder }} |
- {% endif %}
-
-
- | {% trans "Channel" %} |
- {{ object.get_rf_channel_display|placeholder }} |
- {% if peer %}
-
- {{ peer.get_rf_channel_display|placeholder }}
- |
- {% endif %}
-
-
- | {% trans "Channel Frequency" %} |
-
- {% if object.rf_channel_frequency %}
- {{ object.rf_channel_frequency|floatformat:"-2" }} {% trans "MHz" %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
- {% if peer %}
-
- {% if peer.rf_channel_frequency %}
- {{ peer.rf_channel_frequency|floatformat:"-2" }} {% trans "MHz" %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
- {% endif %}
-
-
- | {% trans "Channel Width" %} |
-
- {% if object.rf_channel_width %}
- {{ object.rf_channel_width|floatformat:"-3" }} {% trans "MHz" %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
- {% if peer %}
-
- {% if peer.rf_channel_width %}
- {{ peer.rf_channel_width|floatformat:"-3" }} {% trans "MHz" %}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
- {% endif %}
-
-
- {% endwith %}
-
-
-
-
-
-
- | {% trans "Group" %} |
- {% trans "SSID" %} |
-
-
-
- {% for wlan in object.wireless_lans.all %}
-
- | {{ wlan.group|linkify|placeholder }} |
- {{ wlan|linkify:"ssid" }} |
-
- {% empty %}
-
- | {% trans "None" %} |
-
- {% endfor %}
-
-
-
- {% endif %}
- {% include 'ipam/inc/panels/fhrp_groups.html' %}
- {% include 'dcim/inc/panels/inventory_items.html' %}
- {% plugin_right_page object %}
-
-
-
-
-
-
- {% htmx_table 'ipam:ipaddress_list' interface_id=object.pk %}
-
-
-
-
-
-
-
- {% htmx_table 'dcim:macaddress_list' interface_id=object.pk %}
-
-
-
-
-
-
-
- {% htmx_table 'ipam:vlan_list' interface_id=object.pk %}
-
-
-
- {% if object.is_lag %}
-
-
- {% include 'inc/panel_table.html' with table=lag_interfaces_table heading="LAG Members" %}
-
-
- {% endif %}
- {% if object.vlan_translation_policy %}
-
-
- {% include 'inc/panel_table.html' with table=vlan_translation_table heading="VLAN Translation" %}
-
-
- {% endif %}
-
-
- {% include 'inc/panel_table.html' with table=bridge_interfaces_table heading="Bridged Interfaces" %}
-
-
-
-
- {% include 'inc/panel_table.html' with table=child_interfaces_table heading="Child Interfaces" %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/dcim/interface/attrs/mac_address.html b/netbox/templates/dcim/interface/attrs/mac_address.html
new file mode 100644
index 000000000..abb3c9cb8
--- /dev/null
+++ b/netbox/templates/dcim/interface/attrs/mac_address.html
@@ -0,0 +1,3 @@
+{% load helpers i18n %}
+{{ value|linkify }}
+{% trans "Primary" %}
diff --git a/netbox/templates/dcim/interface/attrs/speed.html b/netbox/templates/dcim/interface/attrs/speed.html
new file mode 100644
index 000000000..fc4b15d28
--- /dev/null
+++ b/netbox/templates/dcim/interface/attrs/speed.html
@@ -0,0 +1,2 @@
+{% load helpers %}
+{{ value|humanize_speed }}
diff --git a/netbox/templates/dcim/panels/interface_connection.html b/netbox/templates/dcim/panels/interface_connection.html
new file mode 100644
index 000000000..ada78f39a
--- /dev/null
+++ b/netbox/templates/dcim/panels/interface_connection.html
@@ -0,0 +1,105 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+ {% if object.mark_connected %}
+
+
+ {% trans "Marked as Connected" %}
+
+ {% elif object.cable %}
+
+
+ | {% trans "Cable" %} |
+
+ {{ object.cable|linkify }}
+
+
+
+ |
+
+
+ | {% trans "Path status" %} |
+
+ {% if object.path.is_complete and object.path.is_active %}
+ {% trans "Reachable" %}
+ {% else %}
+ {% trans "Not Reachable" %}
+ {% endif %}
+ |
+
+
+ | {% trans "Path endpoints" %} |
+
+ {% for endpoint in object.connected_endpoints %}
+ {% if endpoint.parent_object %}
+ {{ endpoint.parent_object|linkify }}
+
+ {% endif %}
+ {{ endpoint|linkify }}
+ {% if not forloop.last %} {% endif %}
+ {% empty %}
+ {{ ''|placeholder }}
+ {% endfor %}
+ |
+
+
+ {% elif object.wireless_link %}
+
+
+ | {% trans "Wireless Link" %} |
+
+ {{ object.wireless_link|linkify }}
+
+
+
+ |
+
+ {% with peer_interface=object.link_peers.0 %}
+
+ | {% trans "Device" %} |
+ {{ peer_interface.device|linkify }} |
+
+
+ | {% trans "Name" %} |
+ {{ peer_interface|linkify }} |
+
+
+ | {% trans "Type" %} |
+ {{ peer_interface.get_type_display }} |
+
+ {% endwith %}
+
+ {% else %}
+
+ {% trans "Not Connected" %}
+ {% if object.is_wired and perms.dcim.add_cable %}
+
+
+
+
+ {% elif object.is_wireless and perms.wireless.add_wirelesslink %}
+
+ {% endif %}
+
+ {% endif %}
+{% endblock panel_content %}
diff --git a/netbox/templates/dcim/panels/interface_virtual_circuit.html b/netbox/templates/dcim/panels/interface_virtual_circuit.html
new file mode 100644
index 000000000..70e0c065c
--- /dev/null
+++ b/netbox/templates/dcim/panels/interface_virtual_circuit.html
@@ -0,0 +1,35 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+
+
+ | {% trans "Provider" %} |
+ {{ object.virtual_circuit_termination.virtual_circuit.provider|linkify }} |
+
+
+ | {% trans "Provider Network" %} |
+ {{ object.virtual_circuit_termination.virtual_circuit.provider_network|linkify }} |
+
+
+ | {% trans "Circuit ID" %} |
+ {{ object.virtual_circuit_termination.virtual_circuit|linkify }} |
+
+
+ | {% trans "Role" %} |
+ {{ object.virtual_circuit_termination.get_role_display }} |
+
+
+ | {% trans "Connections" %} |
+
+ {% for termination in object.virtual_circuit_termination.peer_terminations %}
+ {{ termination.interface.parent_object }}
+
+ {{ termination.interface }}
+ ({{ termination.get_role_display }})
+ {% if not forloop.last %} {% endif %}
+ {% endfor %}
+ |
+
+
+{% endblock panel_content %}
diff --git a/netbox/templates/dcim/panels/interface_wireless.html b/netbox/templates/dcim/panels/interface_wireless.html
new file mode 100644
index 000000000..dfc7a3452
--- /dev/null
+++ b/netbox/templates/dcim/panels/interface_wireless.html
@@ -0,0 +1,72 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+ {% with peer=object.connected_endpoints.0 %}
+
+
+
+ |
+ {% trans "Local" %} |
+ {% if peer %}
+ {% trans "Peer" %} |
+ {% endif %}
+
+
+
+ | {% trans "Role" %} |
+ {{ object.get_rf_role_display|placeholder }} |
+ {% if peer %}
+ {{ peer.get_rf_role_display|placeholder }} |
+ {% endif %}
+
+
+ | {% trans "Channel" %} |
+ {{ object.get_rf_channel_display|placeholder }} |
+ {% if peer %}
+
+ {{ peer.get_rf_channel_display|placeholder }}
+ |
+ {% endif %}
+
+
+ | {% trans "Channel frequency" %} |
+
+ {% if object.rf_channel_frequency %}
+ {{ object.rf_channel_frequency|floatformat:"-2" }} {% trans "MHz" %}
+ {% else %}
+ {{ ''|placeholder }}
+ {% endif %}
+ |
+ {% if peer %}
+
+ {% if peer.rf_channel_frequency %}
+ {{ peer.rf_channel_frequency|floatformat:"-2" }} {% trans "MHz" %}
+ {% else %}
+ {{ ''|placeholder }}
+ {% endif %}
+ |
+ {% endif %}
+
+
+ | {% trans "Channel width" %} |
+
+ {% if object.rf_channel_width %}
+ {{ object.rf_channel_width|floatformat:"-3" }} {% trans "MHz" %}
+ {% else %}
+ {{ ''|placeholder }}
+ {% endif %}
+ |
+ {% if peer %}
+
+ {% if peer.rf_channel_width %}
+ {{ peer.rf_channel_width|floatformat:"-3" }} {% trans "MHz" %}
+ {% else %}
+ {{ ''|placeholder }}
+ {% endif %}
+ |
+ {% endif %}
+
+
+ {% endwith %}
+{% endblock panel_content %}
diff --git a/netbox/templates/dcim/panels/interface_wireless_lans.html b/netbox/templates/dcim/panels/interface_wireless_lans.html
new file mode 100644
index 000000000..30c83101d
--- /dev/null
+++ b/netbox/templates/dcim/panels/interface_wireless_lans.html
@@ -0,0 +1,25 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+
+
+
+ | {% trans "Group" %} |
+ {% trans "SSID" %} |
+
+
+
+ {% for wlan in object.wireless_lans.all %}
+
+ | {{ wlan.group|linkify|placeholder }} |
+ {{ wlan|linkify:"ssid" }} |
+
+ {% empty %}
+
+ | {% trans "None" %} |
+
+ {% endfor %}
+
+
+{% endblock panel_content %}