Skip to content

Commit 77613b3

Browse files
committed
Add panels for common inclusion templates
1 parent 3fd4664 commit 77613b3

File tree

9 files changed

+178
-8
lines changed

9 files changed

+178
-8
lines changed

netbox/dcim/views.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
1919
from netbox.object_actions import *
2020
from netbox.ui import layout
21+
from netbox.ui.panels import CommentsPanel, CustomFieldsPanel, ImageAttachmentsPanel, RelatedObjectsPanel, TagsPanel
2122
from netbox.views import generic
2223
from utilities.forms import ConfirmationForm
2324
from utilities.paginator import EnhancedPaginator, get_paginate_count
@@ -468,14 +469,20 @@ class SiteView(GetRelatedModelsMixin, generic.ObjectView):
468469
layout = layout.Layout(
469470
layout.Row(
470471
layout.Column(
471-
panels.SitePanel(_('Site'))
472+
panels.SitePanel(_('Site')),
473+
CustomFieldsPanel(),
474+
TagsPanel(),
475+
CommentsPanel(),
476+
),
477+
layout.Column(
478+
RelatedObjectsPanel(),
479+
ImageAttachmentsPanel(),
472480
),
473481
)
474482
)
475483

476484
def get_extra_context(self, request, instance):
477485
return {
478-
# 'site_panel': panels.SitePanel(instance, _('Site')),
479486
'related_models': self.get_related_models(
480487
request,
481488
instance,

netbox/netbox/ui/panels.py

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@
88
from utilities.string import title
99

1010
__all__ = (
11+
'CommentsPanel',
12+
'CustomFieldsPanel',
13+
'ImageAttachmentsPanel',
1114
'NestedGroupObjectPanel',
1215
'ObjectPanel',
16+
'RelatedObjectsPanel',
1317
'Panel',
18+
'TagsPanel',
1419
)
1520

1621

1722
class Panel(ABC):
1823

24+
def __init__(self, title=None):
25+
if title is not None:
26+
self.title = title
27+
1928
@abstractmethod
2029
def render(self, obj):
2130
pass
@@ -51,9 +60,6 @@ def __new__(mcls, name, bases, namespace, **kwargs):
5160
class ObjectPanel(Panel, metaclass=ObjectPanelMeta):
5261
template_name = 'ui/panels/object.html'
5362

54-
def __init__(self, title=None):
55-
self.title = title
56-
5763
def get_attributes(self, obj):
5864
return [
5965
{
@@ -74,3 +80,65 @@ class NestedGroupObjectPanel(ObjectPanel, metaclass=ObjectPanelMeta):
7480
name = attrs.TextAttr('name', label=_('Name'))
7581
description = attrs.TextAttr('description', label=_('Description'))
7682
parent = attrs.NestedObjectAttr('parent', label=_('Parent'), linkify=True)
83+
84+
85+
class CustomFieldsPanel(Panel):
86+
template_name = 'ui/panels/custom_fields.html'
87+
title = _('Custom Fields')
88+
89+
def render(self, context):
90+
obj = context.get('object')
91+
custom_fields = obj.get_custom_fields_by_group()
92+
if not custom_fields:
93+
return ''
94+
return render_to_string(self.template_name, {
95+
'title': self.title,
96+
'custom_fields': custom_fields,
97+
})
98+
99+
100+
class TagsPanel(Panel):
101+
template_name = 'ui/panels/tags.html'
102+
title = _('Tags')
103+
104+
def render(self, context):
105+
return render_to_string(self.template_name, {
106+
'title': self.title,
107+
'object': context.get('object'),
108+
})
109+
110+
111+
class CommentsPanel(Panel):
112+
template_name = 'ui/panels/comments.html'
113+
title = _('Comments')
114+
115+
def render(self, context):
116+
obj = context.get('object')
117+
return render_to_string(self.template_name, {
118+
'title': self.title,
119+
'comments': obj.comments,
120+
})
121+
122+
123+
class RelatedObjectsPanel(Panel):
124+
template_name = 'ui/panels/related_objects.html'
125+
title = _('Related Objects')
126+
127+
def render(self, context):
128+
return render_to_string(self.template_name, {
129+
'title': self.title,
130+
'object': context.get('object'),
131+
'related_models': context.get('related_models'),
132+
})
133+
134+
135+
class ImageAttachmentsPanel(Panel):
136+
template_name = 'ui/panels/image_attachments.html'
137+
title = _('Image Attachments')
138+
139+
def render(self, context):
140+
return render_to_string(self.template_name, {
141+
'title': self.title,
142+
'request': context.get('request'),
143+
'object': context.get('object'),
144+
})
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div class="card">
2+
<h2 class="card-header">{{ title }}</h2>
3+
{% block panel_content %}{% endblock %}
4+
</div>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load i18n %}
3+
4+
{% block panel_content %}
5+
<div class="card-body">
6+
{% if comments %}
7+
{{ comments|markdown }}
8+
{% else %}
9+
<span class="text-muted">{% trans "None" %}</span>
10+
{% endif %}
11+
</div>
12+
{% endblock panel_content %}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load i18n %}
3+
4+
{% block panel_content %}
5+
<table class="table table-hover attr-table">
6+
{% for group_name, fields in custom_fields.items %}
7+
{% if group_name %}
8+
<tr>
9+
<th scope="row" colspan="2" class="fw-bold">{{ group_name }}</th>
10+
</tr>
11+
{% endif %}
12+
{% for field, value in fields.items %}
13+
<tr>
14+
<th scope="row"{% if group_name %} class="ps-3"{% endif %}>{{ field }}
15+
{% if field.description %}
16+
<i
17+
class="mdi mdi-information text-primary"
18+
data-bs-toggle="tooltip"
19+
data-bs-placement="right"
20+
title="{{ field.description|escape }}"
21+
></i>
22+
{% endif %}
23+
</th>
24+
<td>
25+
{% customfield_value field value %}
26+
</td>
27+
</tr>
28+
{% endfor %}
29+
{% endfor %}
30+
</table>
31+
{% endblock panel_content %}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load i18n %}
3+
4+
{# TODO: Add "attach an image" button in panel header #}
5+
{% block panel_content %}
6+
{% htmx_table 'extras:imageattachment_list' object_type_id=object|content_type_id object_id=object.pk %}
7+
{% endblock panel_content %}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
<div class="card">
2-
<h2 class="card-header">{{ title }}</h2>
1+
{% extends "ui/panels/_base.html" %}
2+
3+
{% block panel_content %}
34
<table class="table table-hover attr-table">
45
{% for attr in attrs %}
56
<tr>
@@ -10,4 +11,4 @@ <h2 class="card-header">{{ title }}</h2>
1011
</tr>
1112
{% endfor %}
1213
</table>
13-
</div>
14+
{% endblock panel_content %}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load helpers %}
3+
{% load i18n %}
4+
5+
{% block panel_content %}
6+
<ul class="list-group list-group-flush" role="presentation">
7+
{% for related_object_count in related_models %}
8+
{% action_url related_object_count.queryset.model 'list' as list_url %}
9+
{% if list_url %}
10+
<a href="{{ list_url }}?{{ related_object_count.filter_param }}={{ object.pk }}" class="list-group-item list-group-item-action d-flex justify-content-between">
11+
{{ related_object_count.name }}
12+
{% with count=related_object_count.queryset.count %}
13+
{% if count %}
14+
<span class="badge text-bg-primary rounded-pill">{{ count }}</span>
15+
{% else %}
16+
<span class="badge text-bg-light rounded-pill">&mdash;</span>
17+
{% endif %}
18+
{% endwith %}
19+
</a>
20+
{% endif %}
21+
{% empty %}
22+
<span class="list-group-item text-muted">{% trans "None" %}</span>
23+
{% endfor %}
24+
</ul>
25+
{% endblock panel_content %}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load helpers %}
3+
{% load i18n %}
4+
5+
{% block panel_content %}
6+
<div class="card-body">
7+
{% with url=object|validated_viewname:"list" %}
8+
{% for tag in object.tags.all %}
9+
{% tag tag url %}
10+
{% empty %}
11+
<span class="text-muted">{% trans "No tags assigned" %}</span>
12+
{% endfor %}
13+
{% endwith %}
14+
</div>
15+
{% endblock panel_content %}

0 commit comments

Comments
 (0)