Closes #16776: Extend PluginTemplateExtension to render custom alerts for objects (#16889)

* Closes #16776: Extend PluginTemplateExtension to render custom alerts for objects

* Fix bug in _get_registered_content()
This commit is contained in:
Jeremy Stretch 2024-07-12 09:52:07 -04:00 committed by GitHub
parent 02ae91589d
commit 1c2336be60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 30 deletions

View File

@ -196,11 +196,12 @@ Plugins can inject custom content into certain areas of core NetBox views. This
| Method | View | Description | | Method | View | Description |
|---------------------|-------------|-----------------------------------------------------| |---------------------|-------------|-----------------------------------------------------|
| `navbar()` | All | Inject content inside the top navigation bar | | `navbar()` | All | Inject content inside the top navigation bar |
| `list_buttons()` | List view | Add buttons to the top of the page |
| `buttons()` | Object view | Add buttons to the top of the page |
| `alerts()` | Object view | Inject content at the top of the page |
| `left_page()` | Object view | Inject content on the left side of the page | | `left_page()` | Object view | Inject content on the left side of the page |
| `right_page()` | Object view | Inject content on the right side of the page | | `right_page()` | Object view | Inject content on the right side of the page |
| `full_width_page()` | Object view | Inject content across the entire bottom of the page | | `full_width_page()` | Object view | Inject content across the entire bottom of the page |
| `buttons()` | Object view | Add buttons to the top of the page |
| `list_buttons()` | List view | Add buttons to the top of the page |
!!! info "The `navbar()` method was introduced in NetBox v4.1." !!! info "The `navbar()` method was introduced in NetBox v4.1."

View File

@ -38,6 +38,10 @@ class PluginTemplateExtension:
return get_template(template_name).render({**self.context, **extra_context}) return get_template(template_name).render({**self.context, **extra_context})
#
# Global methods
#
def navbar(self): def navbar(self):
""" """
Content that will be rendered inside the top navigation menu. Content should be returned as an HTML Content that will be rendered inside the top navigation menu. Content should be returned as an HTML
@ -45,6 +49,37 @@ class PluginTemplateExtension:
""" """
raise NotImplementedError raise NotImplementedError
#
# Object list views
#
def list_buttons(self):
"""
Buttons that will be rendered and added to the existing list of buttons on the list view. Content
should be returned as an HTML string. Note that content does not need to be marked as safe because this is
automatically handled.
"""
raise NotImplementedError
#
# Object detail views
#
def buttons(self):
"""
Buttons that will be rendered and added to the existing list of buttons on the detail page view. Content
should be returned as an HTML string. Note that content does not need to be marked as safe because this is
automatically handled.
"""
raise NotImplementedError
def alerts(self):
"""
Arbitrary content to be inserted at the top of an object's detail view. Content should be returned as an
HTML string. Note that content does not need to be marked as safe because this is automatically handled.
"""
raise NotImplementedError
def left_page(self): def left_page(self):
""" """
Content that will be rendered on the left of the detail page view. Content should be returned as an Content that will be rendered on the left of the detail page view. Content should be returned as an
@ -65,19 +100,3 @@ class PluginTemplateExtension:
HTML string. Note that content does not need to be marked as safe because this is automatically handled. HTML string. Note that content does not need to be marked as safe because this is automatically handled.
""" """
raise NotImplementedError raise NotImplementedError
def buttons(self):
"""
Buttons that will be rendered and added to the existing list of buttons on the detail page view. Content
should be returned as an HTML string. Note that content does not need to be marked as safe because this is
automatically handled.
"""
raise NotImplementedError
def list_buttons(self):
"""
Buttons that will be rendered and added to the existing list of buttons on the list view. Content
should be returned as an HTML string. Note that content does not need to be marked as safe because this is
automatically handled.
"""
raise NotImplementedError

View File

@ -10,6 +10,12 @@ class GlobalContent(PluginTemplateExtension):
class SiteContent(PluginTemplateExtension): class SiteContent(PluginTemplateExtension):
models = ['dcim.site'] models = ['dcim.site']
def buttons(self):
return "SITE CONTENT - BUTTONS"
def alerts(self):
return "SITE CONTENT - ALERTS"
def left_page(self): def left_page(self):
return "SITE CONTENT - LEFT PAGE" return "SITE CONTENT - LEFT PAGE"
@ -19,9 +25,6 @@ class SiteContent(PluginTemplateExtension):
def full_width_page(self): def full_width_page(self):
return "SITE CONTENT - FULL WIDTH PAGE" return "SITE CONTENT - FULL WIDTH PAGE"
def buttons(self):
return "SITE CONTENT - BUTTONS"
def list_buttons(self): def list_buttons(self):
return "SITE CONTENT - LIST BUTTONS" return "SITE CONTENT - LIST BUTTONS"

View File

@ -110,6 +110,10 @@ Blocks:
<div class="page-body my-1"> <div class="page-body my-1">
<div class="container-fluid tab-content py-3"> <div class="container-fluid tab-content py-3">
{# Page alerts #}
{% block alerts %}{% endblock %}
{# /Page alerts #}
{# Page content #} {# Page content #}
{% block content %}{% endblock %} {% block content %}{% endblock %}
{# /Page content #} {# /Page content #}

View File

@ -111,6 +111,10 @@ Context:
</ul> </ul>
{% endblock tabs %} {% endblock tabs %}
{% block alerts %}
{% plugin_alerts object %}
{% endblock alerts %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
{% block modals %} {% block modals %}

View File

@ -23,7 +23,7 @@ def _get_registered_content(obj, method, template_context):
} }
template_extensions = list(registry['plugins']['template_extensions'].get(None, [])) template_extensions = list(registry['plugins']['template_extensions'].get(None, []))
if obj is not None: if hasattr(obj, '_meta'):
model_name = obj._meta.label_lower model_name = obj._meta.label_lower
template_extensions.extend(registry['plugins']['template_extensions'].get(model_name, [])) template_extensions.extend(registry['plugins']['template_extensions'].get(model_name, []))
for template_extension in template_extensions: for template_extension in template_extensions:
@ -53,6 +53,14 @@ def plugin_navbar(context):
return _get_registered_content(None, 'navbar', context) return _get_registered_content(None, 'navbar', context)
@register.simple_tag(takes_context=True)
def plugin_list_buttons(context, model):
"""
Render all list buttons registered by plugins
"""
return _get_registered_content(model, 'list_buttons', context)
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def plugin_buttons(context, obj): def plugin_buttons(context, obj):
""" """
@ -61,6 +69,14 @@ def plugin_buttons(context, obj):
return _get_registered_content(obj, 'buttons', context) return _get_registered_content(obj, 'buttons', context)
@register.simple_tag(takes_context=True)
def plugin_alerts(context, obj):
"""
Render all object alerts registered by plugins
"""
return _get_registered_content(obj, 'alerts', context)
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def plugin_left_page(context, obj): def plugin_left_page(context, obj):
""" """
@ -83,11 +99,3 @@ def plugin_full_width_page(context, obj):
Render all full width page content registered by plugins Render all full width page content registered by plugins
""" """
return _get_registered_content(obj, 'full_width_page', context) return _get_registered_content(obj, 'full_width_page', context)
@register.simple_tag(takes_context=True)
def plugin_list_buttons(context, model):
"""
Render all list buttons registered by plugins
"""
return _get_registered_content(model, 'list_buttons', context)