Compare commits

...

10 Commits

Author SHA1 Message Date
Brian Tiemann
bc22b1530b Use ManyToManyColumn
CI / build (20.x, 3.13) (push) Failing after 18s
CI / build (20.x, 3.14) (push) Failing after 16s
CI / build (20.x, 3.12) (push) Failing after 20s
2026-02-04 11:12:34 -05:00
Brian Tiemann
8889e865f1 Merge branch 'main' into 19129-mac-address-table-display 2026-02-04 10:43:43 -05:00
Martin Hauser
ee6cbdcefe Fixes #21320: Prevent Rack validation errors when site or optional fields are missing during import (#21321)
CI / build (20.x, 3.12) (push) Failing after 18s
CI / build (20.x, 3.13) (push) Failing after 14s
CI / build (20.x, 3.14) (push) Failing after 12s
CodeQL / Analyze (actions) (push) Failing after 24s
CodeQL / Analyze (javascript-typescript) (push) Failing after 30s
CodeQL / Analyze (python) (push) Failing after 27s
2026-02-03 09:32:07 -06:00
Brian Tiemann
c0ea63da5f Simplify Multiple MAC addresses with additional selectable column for tables in list view and detail view
CI / build (20.x, 3.12) (push) Failing after 1m42s
CI / build (20.x, 3.13) (push) Failing after 12s
CI / build (20.x, 3.14) (push) Failing after 11s
2026-01-28 20:08:47 -05:00
Brian Tiemann
087a2adb3c Also include vminterface.html 2026-01-22 22:16:12 -05:00
Brian Tiemann
a145dbc44a Ensure "-" null placeholder still shows up on detail page 2026-01-22 22:13:12 -05:00
Brian Tiemann
9b1f033c73 Use mac_address_display in interface detail page 2026-01-22 22:08:30 -05:00
Brian Tiemann
60e37e868b Fix docstring 2026-01-22 22:02:40 -05:00
Brian Tiemann
c1287de970 Fix docstring 2026-01-22 22:00:42 -05:00
Brian Tiemann
3891b2a25f Richer display of MAC addresses in InterfaceTable when multiple MACs are present 2026-01-22 21:56:33 -05:00
3 changed files with 26 additions and 17 deletions
+1 -1
View File
@@ -373,7 +373,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, TrackingModelMixin, RackBase):
super().clean() super().clean()
# Validate location/site assignment # Validate location/site assignment
if self.site and self.location and self.location.site != self.site: if self.site_id and self.location_id and self.location.site_id != self.site_id:
raise ValidationError(_("Assigned location must belong to parent site ({site}).").format(site=self.site)) raise ValidationError(_("Assigned location must belong to parent site ({site}).").format(site=self.site))
# Validate outer dimensions and unit # Validate outer dimensions and unit
+23 -14
View File
@@ -584,6 +584,15 @@ class BaseInterfaceTable(NetBoxTable):
orderable=False, orderable=False,
verbose_name=_('IP Addresses') verbose_name=_('IP Addresses')
) )
primary_mac_address = tables.Column(
verbose_name=_('Primary MAC'),
linkify=True
)
mac_addresses = columns.ManyToManyColumn(
orderable=False,
linkify_item=True,
verbose_name=_('MAC Addresses')
)
fhrp_groups = tables.TemplateColumn( fhrp_groups = tables.TemplateColumn(
accessor=Accessor('fhrp_group_assignments'), accessor=Accessor('fhrp_group_assignments'),
template_code=INTERFACE_FHRPGROUPS, template_code=INTERFACE_FHRPGROUPS,
@@ -615,10 +624,6 @@ class BaseInterfaceTable(NetBoxTable):
verbose_name=_('Q-in-Q SVLAN'), verbose_name=_('Q-in-Q SVLAN'),
linkify=True linkify=True
) )
primary_mac_address = tables.Column(
verbose_name=_('MAC Address'),
linkify=True
)
def value_ip_addresses(self, value): def value_ip_addresses(self, value):
return ",".join([str(obj.address) for obj in value.all()]) return ",".join([str(obj.address) for obj in value.all()])
@@ -681,11 +686,12 @@ class InterfaceTable(BaseInterfaceTable, ModularDeviceComponentTable, PathEndpoi
model = models.Interface model = models.Interface
fields = ( fields = (
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu',
'speed', 'speed_formatted', 'duplex', 'mode', 'primary_mac_address', 'wwn', 'poe_mode', 'poe_type', 'speed', 'speed_formatted', 'duplex', 'mode', 'mac_addresses', 'primary_mac_address', 'wwn',
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
'mark_connected', 'cable', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'description', 'mark_connected', 'cable', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer',
'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups',
'qinq_svlan', 'inventory_items', 'created', 'last_updated', 'vlan_translation_policy' 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'inventory_items', 'created', 'last_updated',
'vlan_translation_policy',
) )
default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description') default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')
@@ -746,10 +752,11 @@ class DeviceInterfaceTable(InterfaceTable):
model = models.Interface model = models.Interface
fields = ( fields = (
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag', 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
'mgmt_only', 'mtu', 'mode', 'primary_mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'mgmt_only', 'mtu', 'mode', 'mac_addresses', 'primary_mac_address', 'wwn', 'rf_role', 'rf_channel',
'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable', 'cable_color', 'wireless_link', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable',
'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf',
'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'actions', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan',
'actions',
) )
default_columns = ( default_columns = (
'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses', 'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses',
@@ -1199,4 +1206,6 @@ class MACAddressTable(PrimaryModelTable):
'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description', 'is_primary', 'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description', 'is_primary',
'comments', 'tags', 'created', 'last_updated', 'comments', 'tags', 'created', 'last_updated',
) )
default_columns = ('pk', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description') default_columns = (
'pk', 'mac_address', 'is_primary', 'assigned_object_parent', 'assigned_object', 'description',
)
@@ -78,8 +78,8 @@
<tr> <tr>
<th scope="row">{% trans "MAC Address" %}</th> <th scope="row">{% trans "MAC Address" %}</th>
<td> <td>
{% if object.mac_address %} {% if object.primary_mac_address %}
<span class="font-monospace">{{ object.mac_address }}</span> <span class="font-monospace">{{ object.primary_mac_address|linkify }}</span>
<span class="badge text-bg-primary">{% trans "Primary" %}</span> <span class="badge text-bg-primary">{% trans "Primary" %}</span>
{% else %} {% else %}
{{ ''|placeholder }} {{ ''|placeholder }}