Przeglądaj źródła

#20923: Migrate DCIM view templates (#21372)

* Permit passing template_name to Panel instance

* Define UI layout for ModuleType view

* Define UI layout for DeviceRole view

* Define UI layout for Platform view

* Define UI layout for Module view

* Misc cleanup

* Linkify module bay
Jeremy Stretch 22 godzin temu
rodzic
commit
04244e188f

+ 31 - 0
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.

+ 74 - 0
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 {

+ 6 - 4
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

+ 0 - 64
netbox/templates/dcim/devicerole.html

@@ -15,67 +15,3 @@
     </a>
   {% endif %}
 {% endblock extra_controls %}
-
-{% block content %}
-<div class="row mb-3">
-	<div class="col col-12 col-md-6">
-    <div class="card">
-      <h2 class="card-header">{% trans "Device Role" %}</h2>
-      <table class="table table-hover attr-table">
-        <tr>
-          <th scope="row">{% trans "Name" %}</th>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Description" %}</th>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Parent" %}</th>
-          <td>{{ object.parent|linkify|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Color" %}</th>
-          <td>
-            <span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
-          </td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "VM Role" %}</th>
-          <td>{% checkmark object.vm_role %}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Config Template" %}</th>
-          <td>{{ object.config_template|linkify|placeholder }}</td>
-        </tr>
-      </table>
-    </div>
-    {% include 'inc/panels/tags.html' %}
-    {% plugin_left_page object %}
-	</div>
-	<div class="col col-12 col-md-6">
-    {% include 'inc/panels/related_objects.html' %}
-    {% include 'inc/panels/custom_fields.html' %}
-    {% include 'inc/panels/comments.html' %}
-    {% plugin_right_page object %}
-  </div>
-</div>
-<div class="row mb-3">
-	<div class="col col-md-12">
-    <div class="card">
-      <h2 class="card-header">
-        {% trans "Child Device Roles" %}
-        {% if perms.dcim.add_devicerole %}
-          <div class="card-actions">
-            <a href="{% url 'dcim:devicerole_add' %}?parent={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-ghost-primary btn-sm">
-              <i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a Device Role" %}
-            </a>
-          </div>
-        {% endif %}
-      </h2>
-      {% htmx_table 'dcim:devicerole_list' parent_id=object.pk %}
-    </div>
-    {% plugin_full_width_page object %}
-  </div>
-</div>
-{% endblock %}

+ 0 - 72
netbox/templates/dcim/module.html

@@ -46,75 +46,3 @@
     </div>
   {% endif %}
 {% endblock %}
-
-{% block content %}
-<div class="row">
-	<div class="col col-12 col-md-6">
-    <div class="card">
-      <h2 class="card-header">{% trans "Module" %}</h2>
-      <table class="table table-hover attr-table">
-        <tr>
-          <th scope="row">{% trans "Device" %}</th>
-          <td>{{ object.device|linkify }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Device Type" %}</th>
-          <td>{{ object.device.device_type|linkify }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Module Bay" %}</th>
-          <td>{% nested_tree object.module_bay %}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Status" %}</th>
-          <td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Description" %}</th>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Serial Number" %}</th>
-          <td class="font-monospace">{{ object.serial|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Asset Tag" %}</th>
-          <td class="font-monospace">{{ object.asset_tag|placeholder }}</td>
-        </tr>
-      </table>
-    </div>
-    {% include 'inc/panels/tags.html' %}
-    {% include 'inc/panels/comments.html' %}
-    {% plugin_left_page object %}
-  </div>
-  <div class="col col-12 col-md-6">
-    <div class="card">
-      <h2 class="card-header">{% trans "Module Type" %}</h2>
-      <table class="table table-hover attr-table">
-        <tr>
-          <th scope="row">{% trans "Manufacturer" %}</th>
-          <td>{{ object.module_type.manufacturer|linkify }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Model" %}</th>
-          <td>{{ object.module_type|linkify }}</td>
-        </tr>
-        {% for k, v in object.module_type.attributes.items %}
-          <tr>
-            <th scope="row">{{ k }}</th>
-            <td>{{ v|placeholder }}</td>
-          </tr>
-        {% endfor %}
-      </table>
-    </div>
-    {% include 'inc/panels/related_objects.html' %}
-    {% include 'inc/panels/custom_fields.html' %}
-    {% plugin_right_page object %}
-	</div>
-</div>
-<div class="row">
-  <div class="col col-md-12">
-    {% plugin_full_width_page object %}
-  </div>
-</div>
-{% endblock %}

+ 1 - 91
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 %}
-  <div class="row">
-    <div class="col col-12 col-md-6">
-      <div class="card">
-        <h2 class="card-header">{% trans "Module Type" %}</h2>
-        <table class="table table-hover attr-table">
-          <tr>
-            <th scope="row">{% trans "Profile" %}</th>
-            <td>{{ object.profile|linkify|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Manufacturer" %}</th>
-            <td>{{ object.manufacturer|linkify }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Model Name" %}</th>
-            <td>{{ object.model }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Part Number" %}</th>
-            <td>{{ object.part_number|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Description" %}</th>
-            <td>{{ object.description|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Airflow" %}</th>
-            <td>{{ object.get_airflow_display|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Weight" %}</th>
-            <td>
-            {% if object.weight %}
-              {{ object.weight|floatformat }} {{ object.get_weight_unit_display }}
-            {% else %}
-              {{ ''|placeholder }}
-            {% endif %}
-            </td>
-          </tr>
-        </table>
-      </div>
-      {% include 'inc/panels/tags.html' %}
-      {% include 'inc/panels/comments.html' %}
-      {% plugin_left_page object %}
-    </div>
-    <div class="col col-12 col-md-6">
-      <div class="card">
-        <h2 class="card-header">{% trans "Attributes" %}</h2>
-        {% if not object.profile %}
-          <div class="card-body text-muted">
-            {% trans "No profile assigned" %}
-          </div>
-        {% elif object.attributes %}
-          <table class="table table-hover attr-table">
-            {% for k, v in object.attributes.items %}
-              <tr>
-                <th scope="row">{{ k }}</th>
-                <td>
-                  {% if v is True or v is False %}
-                    {% checkmark v %}
-                  {% else %}
-                    {{ v|placeholder }}
-                  {% endif %}
-                </td>
-              </tr>
-            {% endfor %}
-          </table>
-        {% else %}
-          <div class="card-body text-muted">
-            {% trans "None" %}
-          </div>
-        {% endif %}
-      </div>
-      {% include 'inc/panels/related_objects.html' %}
-      {% include 'inc/panels/custom_fields.html' %}
-      {% include 'inc/panels/image_attachments.html' %}
-      {% plugin_right_page object %}
-    </div>
-  </div>
-  <div class="row">
-    <div class="col col-md-12">
-      {% plugin_full_width_page object %}
-    </div>
-  </div>
+  {% include 'dcim/inc/moduletype_buttons.html' %}
 {% endblock %}

+ 27 - 0
netbox/templates/dcim/panels/module_type.html

@@ -0,0 +1,27 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers i18n %}
+
+{% block panel_content %}
+  <table class="table table-hover attr-table">
+    <tr>
+      <th scope="row">{% trans "Manufacturer" %}</th>
+      <td>{{ object.module_type.manufacturer|linkify }}</td>
+    </tr>
+    <tr>
+      <th scope="row">{% trans "Model" %}</th>
+      <td>{{ object.module_type|linkify }}</td>
+    </tr>
+    {% for k, v in object.module_type.attributes.items %}
+      <tr>
+        <th scope="row">{{ k }}</th>
+        <td>
+          {% if v is True or v is False %}
+            {% checkmark v %}
+          {% else %}
+            {{ v|placeholder }}
+          {% endif %}
+        </td>
+      </tr>
+    {% endfor %}
+  </table>
+{% endblock panel_content %}

+ 29 - 0
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 %}
+    <div class="card-body text-muted">
+      {% trans "No profile assigned" %}
+    </div>
+  {% elif object.attributes %}
+    <table class="table table-hover attr-table">
+      {% for k, v in object.attributes.items %}
+        <tr>
+          <th scope="row">{{ k }}</th>
+          <td>
+            {% if v is True or v is False %}
+              {% checkmark v %}
+            {% else %}
+              {{ v|placeholder }}
+            {% endif %}
+          </td>
+        </tr>
+      {% endfor %}
+    </table>
+  {% else %}
+    <div class="card-body text-muted">
+      {% trans "None" %}
+    </div>
+  {% endif %}
+{% endblock panel_content %}

+ 0 - 58
netbox/templates/dcim/platform.html

@@ -18,61 +18,3 @@
     </a>
   {% endif %}
 {% endblock extra_controls %}
-
-{% block content %}
-<div class="row mb-3">
-	<div class="col col-12 col-md-6">
-    <div class="card">
-      <h2 class="card-header">{% trans "Platform" %}</h2>
-      <table class="table table-hover attr-table">
-        <tr>
-          <th scope="row">{% trans "Name" %}</th>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Description" %}</th>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Parent" %}</th>
-          <td>{{ object.parent|linkify|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Manufacturer" %}</th>
-          <td>{{ object.manufacturer|linkify|placeholder }}</td>
-        </tr>
-        <tr>
-          <th scope="row">{% trans "Config Template" %}</th>
-          <td>{{ object.config_template|linkify|placeholder }}</td>
-        </tr>
-      </table>
-    </div>
-    {% include 'inc/panels/tags.html' %}
-    {% plugin_left_page object %}
-	</div>
-	<div class="col col-12 col-md-6">
-    {% include 'inc/panels/related_objects.html' %}
-    {% include 'inc/panels/custom_fields.html' %}
-    {% include 'inc/panels/comments.html' %}
-    {% plugin_right_page object %}
-  </div>
-</div>
-<div class="row mb-3">
-	<div class="col col-md-12">
-    <div class="card">
-      <h2 class="card-header">
-        {% trans "Child Platforms" %}
-        {% if perms.dcim.add_platform %}
-          <div class="card-actions">
-            <a href="{% url 'dcim:platform_add' %}?parent={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-ghost-primary btn-sm">
-              <i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a Platform" %}
-            </a>
-          </div>
-        {% endif %}
-      </h2>
-      {% htmx_table 'dcim:platform_list' parent_id=object.pk %}
-    </div>
-    {% plugin_full_width_page object %}
-  </div>
-</div>
-{% endblock %}