Adds a new InvenTreePluginMixin mixin class for enabling custom plugin rendering on a page

- Any view which needs custom plugin code must implement this mixin
- Initially implement for the PartDetail page
This commit is contained in:
Oliver Walters 2022-05-06 22:52:52 +10:00
parent 7b8a10173d
commit c80b36fc2f
8 changed files with 74 additions and 10 deletions

View File

@ -38,6 +38,8 @@ from part.models import PartCategory
from common.models import InvenTreeSetting, ColorTheme
from users.models import check_user_role, RuleSet
from plugin.registry import registry
from .forms import DeleteForm, EditUserForm, SetPasswordForm
from .forms import SettingCategorySelectForm
from .helpers import str2bool
@ -56,6 +58,38 @@ def auth_request(request):
return HttpResponse(status=403)
class InvenTreePluginMixin:
"""
Custom view mixin which adds context data to the view,
based on loaded plugins.
This allows rendered pages to be augmented by loaded plugins.
"""
def get_plugin_panels(self):
"""
Return a list of extra 'plugin panels' associated with this view
"""
panels = []
for plug in registry.with_mixin('panel'):
panels += plug.render_panels(self, self.request)
return panels
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
if settings.PLUGINS_ENABLED:
ctx['plugin_panels'] = self.get_plugin_panels()
return ctx
class InvenTreeRoleMixin(PermissionRequiredMixin):
"""
Permission class based on user roles, not user 'permissions'.

View File

@ -397,9 +397,11 @@
</div>
<table class='table table-condensed table-striped' id='manufacturer-part-table' data-toolbar='#manufacturer-button-toolbar'></table>
</div>
</div>
</div>
</div>
{% include "panel/plugin_panels.html" %}
{% endblock %}
{% block js_load %}
@ -1083,4 +1085,6 @@
}
});
{% include "panel/plugin_javascript.html" %}
{% endblock %}

View File

@ -58,3 +58,5 @@
{% include "sidebar_item.html" with label="part-attachments" text=text icon="fa-paperclip" %}
{% trans "Notes" as text %}
{% include "sidebar_item.html" with label="part-notes" text=text icon="fa-clipboard" %}
{% include "panel/plugin_menu_items.html" %}

View File

@ -49,7 +49,7 @@ from order.models import PurchaseOrderLineItem
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.views import QRCodeView
from InvenTree.views import InvenTreeRoleMixin
from InvenTree.views import InvenTreeRoleMixin, InvenTreePluginMixin
from InvenTree.helpers import str2bool
@ -365,7 +365,7 @@ class PartImportAjax(FileManagementAjaxView, PartImport):
return PartImport.validate(self, self.steps.current, form, **kwargs)
class PartDetail(InvenTreeRoleMixin, DetailView):
class PartDetail(InvenTreeRoleMixin, InvenTreePluginMixin, DetailView):
""" Detail view for Part object
"""

View File

@ -46,9 +46,6 @@ class CustomPanelSample(PanelMixin, IntegrationPluginBase):
# This panel will *only* display on the StockLocation view,
# and *only* if the StockLocation has *no* child locations
if isinstance(view, StockLocationDetail):
print("yep, stocklocation view!")
try:
loc = view.get_object()
@ -58,11 +55,7 @@ class CustomPanelSample(PanelMixin, IntegrationPluginBase):
'icon': 'fa-user',
'content': '<h4>I have no children!</h4>'
})
else:
print("abcdefgh")
except:
print("error could not get object!")
pass
return panels

View File

@ -0,0 +1,10 @@
{% if plugin_panels %}
// Run custom javascript when plugin panels are loaded
{% for panel in plugin_panels %}
{% if panel.javascript %}
onPanelLoad('{{ panel.key }}', function() {
{{ panel.javascript | safe }}
});
{% endif %}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,3 @@
{% for panel in plugin_panels %}
{% include "sidebar_item.html" with label=panel.key text=panel.title icon=panel.icon %}
{% endfor %}

View File

@ -0,0 +1,18 @@
{% for panel in plugin_panels %}
<div class='panel panel-hidden' id='panel-{{ panel.key }}'>
<div class='panel-heading'>
<div class='d-flex flex-wrap'>
<h4>{{ panel.title }}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
<!-- TODO: Implement custom action buttons for plugin panels -->
</div>
</div>
</div>
<div class='panel-content'>
{{ panel.content | safe }}
</div>
</div>
{% endfor %}