mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-10 05:42:16 -06:00
Add panels for common inclusion templates
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
netbox/templates/ui/panels/_base.html
Normal file
4
netbox/templates/ui/panels/_base.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div class="card">
|
||||
<h2 class="card-header">{{ title }}</h2>
|
||||
{% block panel_content %}{% endblock %}
|
||||
</div>
|
||||
12
netbox/templates/ui/panels/comments.html
Normal file
12
netbox/templates/ui/panels/comments.html
Normal file
@@ -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
netbox/templates/ui/panels/custom_fields.html
Normal file
31
netbox/templates/ui/panels/custom_fields.html
Normal file
@@ -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
netbox/templates/ui/panels/image_attachments.html
Normal file
7
netbox/templates/ui/panels/image_attachments.html
Normal file
@@ -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 %}
|
||||
@@ -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
netbox/templates/ui/panels/related_objects.html
Normal file
25
netbox/templates/ui/panels/related_objects.html
Normal file
@@ -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">—</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<span class="list-group-item text-muted">{% trans "None" %}</span>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock panel_content %}
|
||||
15
netbox/templates/ui/panels/tags.html
Normal file
15
netbox/templates/ui/panels/tags.html
Normal file
@@ -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 %}
|
||||
Reference in New Issue
Block a user