diff --git a/docs/plugins/development/views.md b/docs/plugins/development/views.md index 9781cfa55a4..cbf920ad563 100644 --- a/docs/plugins/development/views.md +++ b/docs/plugins/development/views.md @@ -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." diff --git a/netbox/netbox/plugins/templates.py b/netbox/netbox/plugins/templates.py index 5fa1959b8a7..e1f4b7a47d1 100644 --- a/netbox/netbox/plugins/templates.py +++ b/netbox/netbox/plugins/templates.py @@ -38,6 +38,10 @@ 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 @@ -45,39 +49,54 @@ def navbar(self): """ 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 diff --git a/netbox/netbox/tests/dummy_plugin/template_content.py b/netbox/netbox/tests/dummy_plugin/template_content.py index b7157e37014..e9a6b9da1ce 100644 --- a/netbox/netbox/tests/dummy_plugin/template_content.py +++ b/netbox/netbox/tests/dummy_plugin/template_content.py @@ -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" @@ -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" diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index 40e371826db..9ab80e0c136 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -110,6 +110,10 @@

+ {# Page alerts #} + {% block alerts %}{% endblock %} + {# /Page alerts #} + {# Page content #} {% block content %}{% endblock %} {# /Page content #} diff --git a/netbox/templates/generic/object.html b/netbox/templates/generic/object.html index bf0e1ae9a3d..e0995f360a1 100644 --- a/netbox/templates/generic/object.html +++ b/netbox/templates/generic/object.html @@ -111,6 +111,10 @@ {% endblock tabs %} +{% block alerts %} + {% plugin_alerts object %} +{% endblock alerts %} + {% block content %}{% endblock %} {% block modals %} diff --git a/netbox/utilities/templatetags/plugins.py b/netbox/utilities/templatetags/plugins.py index 3a5eb734661..16e65d697f1 100644 --- a/netbox/utilities/templatetags/plugins.py +++ b/netbox/utilities/templatetags/plugins.py @@ -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: @@ -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): """ @@ -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): """ @@ -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)