Просмотр исходного кода

Add panels for common inclusion templates

Jeremy Stretch 3 месяцев назад
Родитель
Сommit
77613b37b2

+ 9 - 2
netbox/dcim/views.py

@@ -18,6 +18,7 @@ from ipam.models import ASN, IPAddress, Prefix, VLANGroup, VLAN
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from netbox.object_actions import *
 from netbox.ui import layout
+from netbox.ui.panels import CommentsPanel, CustomFieldsPanel, ImageAttachmentsPanel, RelatedObjectsPanel, TagsPanel
 from netbox.views import generic
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator, get_paginate_count
@@ -468,14 +469,20 @@ class SiteView(GetRelatedModelsMixin, generic.ObjectView):
     layout = layout.Layout(
         layout.Row(
             layout.Column(
-                panels.SitePanel(_('Site'))
+                panels.SitePanel(_('Site')),
+                CustomFieldsPanel(),
+                TagsPanel(),
+                CommentsPanel(),
+            ),
+            layout.Column(
+                RelatedObjectsPanel(),
+                ImageAttachmentsPanel(),
             ),
         )
     )
 
     def get_extra_context(self, request, instance):
         return {
-            # 'site_panel': panels.SitePanel(instance, _('Site')),
             'related_models': self.get_related_models(
                 request,
                 instance,

+ 71 - 3
netbox/netbox/ui/panels.py

@@ -8,14 +8,23 @@ from netbox.ui.attrs import Attr
 from utilities.string import title
 
 __all__ = (
+    'CommentsPanel',
+    'CustomFieldsPanel',
+    'ImageAttachmentsPanel',
     'NestedGroupObjectPanel',
     'ObjectPanel',
+    'RelatedObjectsPanel',
     'Panel',
+    'TagsPanel',
 )
 
 
 class Panel(ABC):
 
+    def __init__(self, title=None):
+        if title is not None:
+            self.title = title
+
     @abstractmethod
     def render(self, obj):
         pass
@@ -51,9 +60,6 @@ class ObjectPanelMeta(ABCMeta):
 class ObjectPanel(Panel, metaclass=ObjectPanelMeta):
     template_name = 'ui/panels/object.html'
 
-    def __init__(self, title=None):
-        self.title = title
-
     def get_attributes(self, obj):
         return [
             {
@@ -74,3 +80,65 @@ class NestedGroupObjectPanel(ObjectPanel, metaclass=ObjectPanelMeta):
     name = attrs.TextAttr('name', label=_('Name'))
     description = attrs.TextAttr('description', label=_('Description'))
     parent = attrs.NestedObjectAttr('parent', label=_('Parent'), linkify=True)
+
+
+class CustomFieldsPanel(Panel):
+    template_name = 'ui/panels/custom_fields.html'
+    title = _('Custom Fields')
+
+    def render(self, context):
+        obj = context.get('object')
+        custom_fields = obj.get_custom_fields_by_group()
+        if not custom_fields:
+            return ''
+        return render_to_string(self.template_name, {
+            'title': self.title,
+            'custom_fields': custom_fields,
+        })
+
+
+class TagsPanel(Panel):
+    template_name = 'ui/panels/tags.html'
+    title = _('Tags')
+
+    def render(self, context):
+        return render_to_string(self.template_name, {
+            'title': self.title,
+            'object': context.get('object'),
+        })
+
+
+class CommentsPanel(Panel):
+    template_name = 'ui/panels/comments.html'
+    title = _('Comments')
+
+    def render(self, context):
+        obj = context.get('object')
+        return render_to_string(self.template_name, {
+            'title': self.title,
+            'comments': obj.comments,
+        })
+
+
+class RelatedObjectsPanel(Panel):
+    template_name = 'ui/panels/related_objects.html'
+    title = _('Related Objects')
+
+    def render(self, context):
+        return render_to_string(self.template_name, {
+            'title': self.title,
+            'object': context.get('object'),
+            'related_models': context.get('related_models'),
+        })
+
+
+class ImageAttachmentsPanel(Panel):
+    template_name = 'ui/panels/image_attachments.html'
+    title = _('Image Attachments')
+
+    def render(self, context):
+        return render_to_string(self.template_name, {
+            'title': self.title,
+            'request': context.get('request'),
+            'object': context.get('object'),
+        })

+ 4 - 0
netbox/templates/ui/panels/_base.html

@@ -0,0 +1,4 @@
+<div class="card">
+  <h2 class="card-header">{{ title }}</h2>
+  {% block panel_content %}{% endblock %}
+</div>

+ 12 - 0
netbox/templates/ui/panels/comments.html

@@ -0,0 +1,12 @@
+{% extends "ui/panels/_base.html" %}
+{% load i18n %}
+
+{% block panel_content %}
+  <div class="card-body">
+    {% if comments %}
+      {{ comments|markdown }}
+    {% else %}
+      <span class="text-muted">{% trans "None" %}</span>
+    {% endif %}
+  </div>
+{% endblock panel_content %}

+ 31 - 0
netbox/templates/ui/panels/custom_fields.html

@@ -0,0 +1,31 @@
+{% extends "ui/panels/_base.html" %}
+{% load i18n %}
+
+{% block panel_content %}
+  <table class="table table-hover attr-table">
+    {% for group_name, fields in custom_fields.items %}
+      {% if group_name %}
+        <tr>
+          <th scope="row" colspan="2" class="fw-bold">{{ group_name }}</th>
+        </tr>
+      {% endif %}
+      {% for field, value in fields.items %}
+        <tr>
+          <th scope="row"{% if group_name %} class="ps-3"{% endif %}>{{ field }}
+            {% if field.description %}
+              <i
+                class="mdi mdi-information text-primary"
+                data-bs-toggle="tooltip"
+                data-bs-placement="right"
+                title="{{ field.description|escape }}"
+              ></i>
+            {% endif %}
+          </th>
+          <td>
+            {% customfield_value field value %}
+          </td>
+        </tr>
+      {% endfor %}
+    {% endfor %}
+  </table>
+{% endblock panel_content %}

+ 7 - 0
netbox/templates/ui/panels/image_attachments.html

@@ -0,0 +1,7 @@
+{% extends "ui/panels/_base.html" %}
+{% load i18n %}
+
+{# TODO: Add "attach an image" button in panel header #}
+{% block panel_content %}
+  {% htmx_table 'extras:imageattachment_list' object_type_id=object|content_type_id object_id=object.pk %}
+{% endblock panel_content %}

+ 4 - 3
netbox/templates/ui/panels/object.html

@@ -1,5 +1,6 @@
-<div class="card">
-  <h2 class="card-header">{{ title }}</h2>
+{% extends "ui/panels/_base.html" %}
+
+{% block panel_content %}
   <table class="table table-hover attr-table">
     {% for attr in attrs %}
       <tr>
@@ -10,4 +11,4 @@
       </tr>
     {% endfor %}
   </table>
-</div>
+{% endblock panel_content %}

+ 25 - 0
netbox/templates/ui/panels/related_objects.html

@@ -0,0 +1,25 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers %}
+{% load i18n %}
+
+{% block panel_content %}
+  <ul class="list-group list-group-flush" role="presentation">
+    {% for related_object_count in related_models %}
+      {% action_url related_object_count.queryset.model 'list' as list_url %}
+      {% if list_url %}
+        <a href="{{ list_url }}?{{ related_object_count.filter_param }}={{ object.pk }}" class="list-group-item list-group-item-action d-flex justify-content-between">
+          {{ related_object_count.name }}
+          {% with count=related_object_count.queryset.count %}
+            {% if count %}
+              <span class="badge text-bg-primary rounded-pill">{{ count }}</span>
+            {% else %}
+              <span class="badge text-bg-light rounded-pill">&mdash;</span>
+            {% endif %}
+          {% endwith %}
+        </a>
+      {% endif %}
+    {% empty %}
+      <span class="list-group-item text-muted">{% trans "None" %}</span>
+    {% endfor %}
+  </ul>
+{% endblock panel_content %}

+ 15 - 0
netbox/templates/ui/panels/tags.html

@@ -0,0 +1,15 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers %}
+{% load i18n %}
+
+{% block panel_content %}
+  <div class="card-body">
+    {% with url=object|validated_viewname:"list" %}
+      {% for tag in object.tags.all %}
+        {% tag tag url %}
+      {% empty %}
+        <span class="text-muted">{% trans "No tags assigned" %}</span>
+      {% endfor %}
+    {% endwith %}
+  </div>
+{% endblock panel_content %}