Skip to content

Commit

Permalink
Closes #16776: Extend PluginTemplateExtension to render custom alerts…
Browse files Browse the repository at this point in the history
… for objects (#16889)

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

* Fix bug in _get_registered_content()
  • Loading branch information
jeremystretch authored Jul 12, 2024
1 parent 02ae915 commit 1c2336b
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 29 deletions.
5 changes: 3 additions & 2 deletions docs/plugins/development/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,12 @@ Plugins can inject custom content into certain areas of core NetBox views. This
| Method | View | Description |
|---------------------|-------------|-----------------------------------------------------|
| `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 |
| `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 |
| `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."

Expand Down
49 changes: 34 additions & 15 deletions netbox/netbox/plugins/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,46 +38,65 @@ def render(self, template_name, extra_context=None):

return get_template(template_name).render({**self.context, **extra_context})

#
# Global methods
#

def navbar(self):
"""
Content that will be rendered inside the top navigation menu. 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):
#
# Object list views
#

def list_buttons(self):
"""
Content that will be rendered on the left of 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.
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

def right_page(self):
#
# Object detail views
#

def buttons(self):
"""
Content that will be rendered on the right of the detail page view. Content should be returned as an
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 full_width_page(self):
def left_page(self):
"""
Content that will be rendered within the full width 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
HTML string. Note that content does not need to be marked as safe because this is automatically handled.
"""
raise NotImplementedError

def buttons(self):
def right_page(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.
Content that will be rendered on the right of 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):
def full_width_page(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.
Content that will be rendered within the full width of 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
9 changes: 6 additions & 3 deletions netbox/netbox/tests/dummy_plugin/template_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ def navbar(self):
class SiteContent(PluginTemplateExtension):
models = ['dcim.site']

def buttons(self):
return "SITE CONTENT - BUTTONS"

def alerts(self):
return "SITE CONTENT - ALERTS"

def left_page(self):
return "SITE CONTENT - LEFT PAGE"

Expand All @@ -19,9 +25,6 @@ def right_page(self):
def full_width_page(self):
return "SITE CONTENT - FULL WIDTH PAGE"

def buttons(self):
return "SITE CONTENT - BUTTONS"

def list_buttons(self):
return "SITE CONTENT - LIST BUTTONS"

Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/base/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ <h1 class="navbar-brand navbar-brand-autodark">
<div class="page-body my-1">
<div class="container-fluid tab-content py-3">

{# Page alerts #}
{% block alerts %}{% endblock %}
{# /Page alerts #}

{# Page content #}
{% block content %}{% endblock %}
{# /Page content #}
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/generic/object.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
</ul>
{% endblock tabs %}

{% block alerts %}
{% plugin_alerts object %}
{% endblock alerts %}

{% block content %}{% endblock %}

{% block modals %}
Expand Down
26 changes: 17 additions & 9 deletions netbox/utilities/templatetags/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def _get_registered_content(obj, method, template_context):
}

template_extensions = list(registry['plugins']['template_extensions'].get(None, []))
if obj is not None:
if hasattr(obj, '_meta'):
model_name = obj._meta.label_lower
template_extensions.extend(registry['plugins']['template_extensions'].get(model_name, []))
for template_extension in template_extensions:
Expand Down Expand Up @@ -53,6 +53,14 @@ def plugin_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)
def plugin_buttons(context, obj):
"""
Expand All @@ -61,6 +69,14 @@ def plugin_buttons(context, obj):
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)
def plugin_left_page(context, obj):
"""
Expand All @@ -83,11 +99,3 @@ def plugin_full_width_page(context, obj):
Render all full width page content registered by plugins
"""
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)

0 comments on commit 1c2336b

Please sign in to comment.