diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index d5382fa26..5b1923b08 100644 --- a/netbox/dcim/views.py +++ b/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, diff --git a/netbox/netbox/ui/panels.py b/netbox/netbox/ui/panels.py index 15cad0a64..96061d42e 100644 --- a/netbox/netbox/ui/panels.py +++ b/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'), + }) diff --git a/netbox/templates/ui/panels/_base.html b/netbox/templates/ui/panels/_base.html new file mode 100644 index 000000000..e1a6b4196 --- /dev/null +++ b/netbox/templates/ui/panels/_base.html @@ -0,0 +1,4 @@ +
| {{ group_name }} | +|
|---|---|
| {{ field }} + {% if field.description %} + + {% endif %} + | ++ {% customfield_value field value %} + | +