mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 12:06:44 +00:00
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:
parent
7b8a10173d
commit
c80b36fc2f
@ -38,6 +38,8 @@ from part.models import PartCategory
|
|||||||
from common.models import InvenTreeSetting, ColorTheme
|
from common.models import InvenTreeSetting, ColorTheme
|
||||||
from users.models import check_user_role, RuleSet
|
from users.models import check_user_role, RuleSet
|
||||||
|
|
||||||
|
from plugin.registry import registry
|
||||||
|
|
||||||
from .forms import DeleteForm, EditUserForm, SetPasswordForm
|
from .forms import DeleteForm, EditUserForm, SetPasswordForm
|
||||||
from .forms import SettingCategorySelectForm
|
from .forms import SettingCategorySelectForm
|
||||||
from .helpers import str2bool
|
from .helpers import str2bool
|
||||||
@ -56,6 +58,38 @@ def auth_request(request):
|
|||||||
return HttpResponse(status=403)
|
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):
|
class InvenTreeRoleMixin(PermissionRequiredMixin):
|
||||||
"""
|
"""
|
||||||
Permission class based on user roles, not user 'permissions'.
|
Permission class based on user roles, not user 'permissions'.
|
||||||
|
@ -397,9 +397,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<table class='table table-condensed table-striped' id='manufacturer-part-table' data-toolbar='#manufacturer-button-toolbar'></table>
|
<table class='table table-condensed table-striped' id='manufacturer-part-table' data-toolbar='#manufacturer-button-toolbar'></table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% include "panel/plugin_panels.html" %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_load %}
|
{% block js_load %}
|
||||||
@ -1083,4 +1085,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{% include "panel/plugin_javascript.html" %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -58,3 +58,5 @@
|
|||||||
{% include "sidebar_item.html" with label="part-attachments" text=text icon="fa-paperclip" %}
|
{% include "sidebar_item.html" with label="part-attachments" text=text icon="fa-paperclip" %}
|
||||||
{% trans "Notes" as text %}
|
{% trans "Notes" as text %}
|
||||||
{% include "sidebar_item.html" with label="part-notes" text=text icon="fa-clipboard" %}
|
{% include "sidebar_item.html" with label="part-notes" text=text icon="fa-clipboard" %}
|
||||||
|
|
||||||
|
{% include "panel/plugin_menu_items.html" %}
|
@ -49,7 +49,7 @@ from order.models import PurchaseOrderLineItem
|
|||||||
|
|
||||||
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||||
from InvenTree.views import QRCodeView
|
from InvenTree.views import QRCodeView
|
||||||
from InvenTree.views import InvenTreeRoleMixin
|
from InvenTree.views import InvenTreeRoleMixin, InvenTreePluginMixin
|
||||||
|
|
||||||
from InvenTree.helpers import str2bool
|
from InvenTree.helpers import str2bool
|
||||||
|
|
||||||
@ -365,7 +365,7 @@ class PartImportAjax(FileManagementAjaxView, PartImport):
|
|||||||
return PartImport.validate(self, self.steps.current, form, **kwargs)
|
return PartImport.validate(self, self.steps.current, form, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PartDetail(InvenTreeRoleMixin, DetailView):
|
class PartDetail(InvenTreeRoleMixin, InvenTreePluginMixin, DetailView):
|
||||||
""" Detail view for Part object
|
""" Detail view for Part object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -46,9 +46,6 @@ class CustomPanelSample(PanelMixin, IntegrationPluginBase):
|
|||||||
# This panel will *only* display on the StockLocation view,
|
# This panel will *only* display on the StockLocation view,
|
||||||
# and *only* if the StockLocation has *no* child locations
|
# and *only* if the StockLocation has *no* child locations
|
||||||
if isinstance(view, StockLocationDetail):
|
if isinstance(view, StockLocationDetail):
|
||||||
|
|
||||||
print("yep, stocklocation view!")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
loc = view.get_object()
|
loc = view.get_object()
|
||||||
|
|
||||||
@ -58,11 +55,7 @@ class CustomPanelSample(PanelMixin, IntegrationPluginBase):
|
|||||||
'icon': 'fa-user',
|
'icon': 'fa-user',
|
||||||
'content': '<h4>I have no children!</h4>'
|
'content': '<h4>I have no children!</h4>'
|
||||||
})
|
})
|
||||||
else:
|
|
||||||
print("abcdefgh")
|
|
||||||
|
|
||||||
except:
|
except:
|
||||||
print("error could not get object!")
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return panels
|
return panels
|
||||||
|
10
InvenTree/templates/panel/plugin_javascript.html
Normal file
10
InvenTree/templates/panel/plugin_javascript.html
Normal 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 %}
|
3
InvenTree/templates/panel/plugin_menu_items.html
Normal file
3
InvenTree/templates/panel/plugin_menu_items.html
Normal 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 %}
|
18
InvenTree/templates/panel/plugin_panels.html
Normal file
18
InvenTree/templates/panel/plugin_panels.html
Normal 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 %}
|
Loading…
x
Reference in New Issue
Block a user