diff --git a/netbox/dcim/ui/panels.py b/netbox/dcim/ui/panels.py
index 67f7d0f32..fa7ad848a 100644
--- a/netbox/dcim/ui/panels.py
+++ b/netbox/dcim/ui/panels.py
@@ -137,6 +137,12 @@ class DeviceDimensionsPanel(panels.ObjectAttributesPanel):
total_weight = attrs.TemplatedAttr('total_weight', template_name='dcim/device/attrs/total_weight.html')
+class DeviceRolePanel(panels.NestedGroupObjectPanel):
+ color = attrs.ColorAttr('color')
+ vm_role = attrs.BooleanAttr('vm_role', label=_('VM role'))
+ config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
+
+
class DeviceTypePanel(panels.ObjectAttributesPanel):
manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
model = attrs.TextAttr('model')
@@ -153,11 +159,36 @@ class DeviceTypePanel(panels.ObjectAttributesPanel):
rear_image = attrs.ImageAttr('rear_image')
+class ModulePanel(panels.ObjectAttributesPanel):
+ device = attrs.RelatedObjectAttr('device', linkify=True)
+ device_type = attrs.RelatedObjectAttr('device.device_type', linkify=True, grouped_by='manufacturer')
+ module_bay = attrs.NestedObjectAttr('module_bay', linkify=True)
+ status = attrs.ChoiceAttr('status')
+ description = attrs.TextAttr('description')
+ serial = attrs.TextAttr('serial', label=_('Serial number'), style='font-monospace', copy_button=True)
+ asset_tag = attrs.TextAttr('asset_tag', style='font-monospace', copy_button=True)
+
+
class ModuleTypeProfilePanel(panels.ObjectAttributesPanel):
name = attrs.TextAttr('name')
description = attrs.TextAttr('description')
+class ModuleTypePanel(panels.ObjectAttributesPanel):
+ profile = attrs.RelatedObjectAttr('profile', linkify=True)
+ manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
+ model = attrs.TextAttr('model', label=_('Model name'))
+ part_number = attrs.TextAttr('part_number')
+ description = attrs.TextAttr('description')
+ airflow = attrs.ChoiceAttr('airflow')
+ weight = attrs.NumericAttr('weight', unit_accessor='get_weight_unit_display')
+
+
+class PlatformPanel(panels.NestedGroupObjectPanel):
+ manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
+ config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
+
+
class VirtualChassisMembersPanel(panels.ObjectPanel):
"""
A panel which lists all members of a virtual chassis.
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
index 617df8d2c..a2b0b6f31 100644
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -25,6 +25,7 @@ from netbox.ui.panels import (
NestedGroupObjectPanel,
ObjectsTablePanel,
OrganizationalObjectPanel,
+ Panel,
RelatedObjectsPanel,
TemplatePanel,
)
@@ -1667,6 +1668,22 @@ class ModuleTypeListView(generic.ObjectListView):
@register_model_view(ModuleType)
class ModuleTypeView(GetRelatedModelsMixin, generic.ObjectView):
queryset = ModuleType.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.ModuleTypePanel(),
+ TagsPanel(),
+ CommentsPanel(),
+ ],
+ right_panels=[
+ Panel(
+ title=_('Attributes'),
+ template_name='dcim/panels/module_type_attributes.html',
+ ),
+ RelatedObjectsPanel(),
+ CustomFieldsPanel(),
+ ImageAttachmentsPanel(),
+ ],
+ )
def get_extra_context(self, request, instance):
return {
@@ -2306,6 +2323,27 @@ class DeviceRoleListView(generic.ObjectListView):
@register_model_view(DeviceRole)
class DeviceRoleView(GetRelatedModelsMixin, generic.ObjectView):
queryset = DeviceRole.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.DeviceRolePanel(),
+ TagsPanel(),
+ ],
+ right_panels=[
+ RelatedObjectsPanel(),
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ model='dcim.DeviceRole',
+ title=_('Child Device Roles'),
+ filters={'parent_id': lambda ctx: ctx['object'].pk},
+ actions=[
+ actions.AddObject('dcim.DeviceRole', url_params={'parent': lambda ctx: ctx['object'].pk}),
+ ],
+ ),
+ ]
+ )
def get_extra_context(self, request, instance):
return {
@@ -2385,6 +2423,27 @@ class PlatformListView(generic.ObjectListView):
@register_model_view(Platform)
class PlatformView(GetRelatedModelsMixin, generic.ObjectView):
queryset = Platform.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.PlatformPanel(),
+ TagsPanel(),
+ ],
+ right_panels=[
+ RelatedObjectsPanel(),
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ model='dcim.Platform',
+ title=_('Child Platforms'),
+ filters={'parent_id': lambda ctx: ctx['object'].pk},
+ actions=[
+ actions.AddObject('dcim.Platform', url_params={'parent': lambda ctx: ctx['object'].pk}),
+ ],
+ ),
+ ]
+ )
def get_extra_context(self, request, instance):
return {
@@ -2778,6 +2837,21 @@ class ModuleListView(generic.ObjectListView):
@register_model_view(Module)
class ModuleView(GetRelatedModelsMixin, generic.ObjectView):
queryset = Module.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.ModulePanel(),
+ TagsPanel(),
+ CommentsPanel(),
+ ],
+ right_panels=[
+ Panel(
+ title=_('Module Type'),
+ template_name='dcim/panels/module_type.html',
+ ),
+ RelatedObjectsPanel(),
+ CustomFieldsPanel(),
+ ],
+ )
def get_extra_context(self, request, instance):
return {
diff --git a/netbox/netbox/ui/panels.py b/netbox/netbox/ui/panels.py
index 55e36b704..9f4be94db 100644
--- a/netbox/netbox/ui/panels.py
+++ b/netbox/netbox/ui/panels.py
@@ -44,15 +44,18 @@ class Panel:
Parameters:
title (str): The human-friendly title of the panel
actions (list): An iterable of PanelActions to include in the panel header
+ template_name (str): Overrides the default template name, if defined
"""
template_name = None
title = None
actions = None
- def __init__(self, title=None, actions=None):
+ def __init__(self, title=None, actions=None, template_name=None):
if title is not None:
self.title = title
self.actions = actions or self.actions or []
+ if template_name is not None:
+ self.template_name = template_name
def get_context(self, context):
"""
@@ -317,9 +320,8 @@ class TemplatePanel(Panel):
Parameters:
template_name (str): The name of the template to render
"""
- def __init__(self, template_name, **kwargs):
- super().__init__(**kwargs)
- self.template_name = template_name
+ def __init__(self, template_name):
+ super().__init__(template_name=template_name)
def render(self, context):
# Pass the entire context to the template
diff --git a/netbox/templates/dcim/devicerole.html b/netbox/templates/dcim/devicerole.html
index 5cce95d23..72fdbd3ed 100644
--- a/netbox/templates/dcim/devicerole.html
+++ b/netbox/templates/dcim/devicerole.html
@@ -15,67 +15,3 @@
{% endif %}
{% endblock extra_controls %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Parent" %} |
- {{ object.parent|linkify|placeholder }} |
-
-
- | {% trans "Color" %} |
-
-
- |
-
-
- | {% trans "VM Role" %} |
- {% checkmark object.vm_role %} |
-
-
- | {% trans "Config Template" %} |
- {{ object.config_template|linkify|placeholder }} |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/related_objects.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_right_page object %}
-
-
-
-
-
-
- {% htmx_table 'dcim:devicerole_list' parent_id=object.pk %}
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/dcim/module.html b/netbox/templates/dcim/module.html
index f9aecb3f0..a39eccf4d 100644
--- a/netbox/templates/dcim/module.html
+++ b/netbox/templates/dcim/module.html
@@ -46,75 +46,3 @@
{% endif %}
{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Device" %} |
- {{ object.device|linkify }} |
-
-
- | {% trans "Device Type" %} |
- {{ object.device.device_type|linkify }} |
-
-
- | {% trans "Module Bay" %} |
- {% nested_tree object.module_bay %} |
-
-
- | {% trans "Status" %} |
- {% badge object.get_status_display bg_color=object.get_status_color %} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Serial Number" %} |
- {{ object.serial|placeholder }} |
-
-
- | {% trans "Asset Tag" %} |
- {{ object.asset_tag|placeholder }} |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_left_page object %}
-
-
-
-
-
-
- | {% trans "Manufacturer" %} |
- {{ object.module_type.manufacturer|linkify }} |
-
-
- | {% trans "Model" %} |
- {{ object.module_type|linkify }} |
-
- {% for k, v in object.module_type.attributes.items %}
-
- | {{ k }} |
- {{ v|placeholder }} |
-
- {% endfor %}
-
-
- {% include 'inc/panels/related_objects.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% plugin_right_page object %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/dcim/moduletype.html b/netbox/templates/dcim/moduletype.html
index 691ff1636..d782c1c27 100644
--- a/netbox/templates/dcim/moduletype.html
+++ b/netbox/templates/dcim/moduletype.html
@@ -1,7 +1,4 @@
{% extends 'generic/object.html' %}
-{% load buttons %}
-{% load helpers %}
-{% load plugins %}
{% load i18n %}
{% block title %}{{ object.manufacturer }} {{ object.model }}{% endblock %}
@@ -14,92 +11,5 @@
{% endblock %}
{% block extra_controls %}
- {% include 'dcim/inc/moduletype_buttons.html' %}
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Profile" %} |
- {{ object.profile|linkify|placeholder }} |
-
-
- | {% trans "Manufacturer" %} |
- {{ object.manufacturer|linkify }} |
-
-
- | {% trans "Model Name" %} |
- {{ object.model }} |
-
-
- | {% trans "Part Number" %} |
- {{ object.part_number|placeholder }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Airflow" %} |
- {{ object.get_airflow_display|placeholder }} |
-
-
- | {% trans "Weight" %} |
-
- {% if object.weight %}
- {{ object.weight|floatformat }} {{ object.get_weight_unit_display }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_left_page object %}
-
-
-
-
- {% if not object.profile %}
-
- {% trans "No profile assigned" %}
-
- {% elif object.attributes %}
-
- {% for k, v in object.attributes.items %}
-
- | {{ k }} |
-
- {% if v is True or v is False %}
- {% checkmark v %}
- {% else %}
- {{ v|placeholder }}
- {% endif %}
- |
-
- {% endfor %}
-
- {% else %}
-
- {% trans "None" %}
-
- {% endif %}
-
- {% include 'inc/panels/related_objects.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/image_attachments.html' %}
- {% plugin_right_page object %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
+ {% include 'dcim/inc/moduletype_buttons.html' %}
{% endblock %}
diff --git a/netbox/templates/dcim/panels/module_type.html b/netbox/templates/dcim/panels/module_type.html
new file mode 100644
index 000000000..7fb90470b
--- /dev/null
+++ b/netbox/templates/dcim/panels/module_type.html
@@ -0,0 +1,27 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+
+
+ | {% trans "Manufacturer" %} |
+ {{ object.module_type.manufacturer|linkify }} |
+
+
+ | {% trans "Model" %} |
+ {{ object.module_type|linkify }} |
+
+ {% for k, v in object.module_type.attributes.items %}
+
+ | {{ k }} |
+
+ {% if v is True or v is False %}
+ {% checkmark v %}
+ {% else %}
+ {{ v|placeholder }}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+{% endblock panel_content %}
diff --git a/netbox/templates/dcim/panels/module_type_attributes.html b/netbox/templates/dcim/panels/module_type_attributes.html
new file mode 100644
index 000000000..85907686d
--- /dev/null
+++ b/netbox/templates/dcim/panels/module_type_attributes.html
@@ -0,0 +1,29 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+ {% if not object.profile %}
+
+ {% trans "No profile assigned" %}
+
+ {% elif object.attributes %}
+
+ {% for k, v in object.attributes.items %}
+
+ | {{ k }} |
+
+ {% if v is True or v is False %}
+ {% checkmark v %}
+ {% else %}
+ {{ v|placeholder }}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+ {% else %}
+
+ {% trans "None" %}
+
+ {% endif %}
+{% endblock panel_content %}
diff --git a/netbox/templates/dcim/platform.html b/netbox/templates/dcim/platform.html
index 4becc042b..26179d4a2 100644
--- a/netbox/templates/dcim/platform.html
+++ b/netbox/templates/dcim/platform.html
@@ -18,61 +18,3 @@
{% endif %}
{% endblock extra_controls %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Parent" %} |
- {{ object.parent|linkify|placeholder }} |
-
-
- | {% trans "Manufacturer" %} |
- {{ object.manufacturer|linkify|placeholder }} |
-
-
- | {% trans "Config Template" %} |
- {{ object.config_template|linkify|placeholder }} |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/related_objects.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_right_page object %}
-
-
-
-
-
-
- {% htmx_table 'dcim:platform_list' parent_id=object.pk %}
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}