mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds a new "Panel" mixin which can render custom panels on given pages
- Adds item to sidebar menu - Adds panel content - Runs custom javascript when the page is loaded
This commit is contained in:
parent
28e16616e5
commit
7b8a10173d
@ -9,6 +9,8 @@ import requests
|
||||
from django.urls import include, re_path
|
||||
from django.db.utils import OperationalError, ProgrammingError
|
||||
|
||||
import InvenTree.helpers
|
||||
|
||||
from plugin.models import PluginConfig, PluginSetting
|
||||
from plugin.urls import PLUGIN_BASE
|
||||
from plugin.helpers import MixinImplementationError, MixinNotImplementedError
|
||||
@ -563,26 +565,72 @@ class PanelMixin:
|
||||
|
||||
This method is provided with:
|
||||
|
||||
- page: The name of the page e.g. 'part-detail'
|
||||
- instance: The model instance specific to the page
|
||||
- request: The request object responsible for the page load
|
||||
|
||||
It must return a list of CustomPanel class instances (see below).
|
||||
- view : The View object which is being rendered
|
||||
- request : The HTTPRequest object
|
||||
|
||||
Note that as this is called dynamically (per request),
|
||||
then the actual panels returned can vary depending on the particular request or page
|
||||
|
||||
"""
|
||||
The 'get_custom_panels' method must return a list of dict objects, each with the following keys:
|
||||
|
||||
class CustomPanel:
|
||||
...
|
||||
- title : The title of the panel, to appear in the sidebar menu
|
||||
- description : Extra descriptive text (optional)
|
||||
- icon : The icon to appear in the sidebar menu
|
||||
- content : The HTML content to appear in the panel, OR
|
||||
- content_template : A template file which will be rendered to produce the panel content
|
||||
- javascript : The javascript content to be rendered when the panel is loade, OR
|
||||
- javascript_template : A template file which will be rendered to produce javascript
|
||||
|
||||
e.g.
|
||||
|
||||
{
|
||||
'title': "Updates",
|
||||
'description': "Latest updates for this part",
|
||||
'javascript': 'alert("You just loaded this panel!")',
|
||||
'content': '<b>Hello world</b>',
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
class MixinMeta:
|
||||
MIXIN_NAME = 'Panel'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.add_mixin('panel', True, __class__)
|
||||
|
||||
def get_custom_panels(self, page, instance, request):
|
||||
|
||||
def render_panels(self, view, request):
|
||||
|
||||
panels = []
|
||||
|
||||
for panel in self.get_custom_panels(view, request):
|
||||
|
||||
if 'content_template' in panel:
|
||||
# TODO: Render the actual content
|
||||
...
|
||||
|
||||
if 'javascript_template' in panel:
|
||||
# TODO: Render the actual content
|
||||
...
|
||||
|
||||
# Check for required keys
|
||||
required_keys = ['title', 'content']
|
||||
|
||||
if any([key not in panel for key in required_keys]):
|
||||
logger.warning(f"Custom panel for plugin '{__class__}' is missing a required key")
|
||||
continue
|
||||
|
||||
# Add some information on this plugin
|
||||
panel['plugin'] = self
|
||||
panel['slug'] = self.slug
|
||||
|
||||
# Add a 'key' for the panel, which is mostly guaranteed to be unique
|
||||
panel['key'] = InvenTree.helpers.generateTestKey(self.slug + panel.get('title', 'panel'))
|
||||
|
||||
panels.append(panel)
|
||||
|
||||
return panels
|
||||
|
||||
def get_custom_panels(self, view, request):
|
||||
""" This method *must* be implemented by the plugin class """
|
||||
raise NotImplementedError(f"{__class__} is missing the 'get_custom_panels' method")
|
||||
|
@ -307,14 +307,17 @@ class PluginsRegistry:
|
||||
# TODO check more stuff -> as of Nov 2021 there are not many checks in place
|
||||
# but we could enhance those to check signatures, run the plugin against a whitelist etc.
|
||||
logger.info(f'Loading integration plugin {plugin.PLUGIN_NAME}')
|
||||
|
||||
try:
|
||||
plugin = plugin()
|
||||
except Exception as error:
|
||||
# log error and raise it -> disable plugin
|
||||
handle_error(error, log_name='init')
|
||||
|
||||
logger.info(f'Loaded integration plugin {plugin.slug}')
|
||||
logger.debug(f'Loaded integration plugin {plugin.PLUGIN_NAME}')
|
||||
|
||||
plugin.is_package = was_packaged
|
||||
|
||||
if plugin_db_setting:
|
||||
plugin.pk = plugin_db_setting.pk
|
||||
|
||||
|
@ -5,6 +5,9 @@ Sample plugin which renders custom panels on certain pages
|
||||
from plugin import IntegrationPluginBase
|
||||
from plugin.mixins import PanelMixin
|
||||
|
||||
from part.views import PartDetail
|
||||
from stock.views import StockLocationDetail
|
||||
|
||||
|
||||
class CustomPanelSample(PanelMixin, IntegrationPluginBase):
|
||||
"""
|
||||
@ -15,8 +18,51 @@ class CustomPanelSample(PanelMixin, IntegrationPluginBase):
|
||||
PLUGIN_SLUG = "panel"
|
||||
PLUGIN_TITLE = "Custom Panel Example"
|
||||
|
||||
def get_custom_panels(self, page, instance, request):
|
||||
def get_custom_panels(self, view, request):
|
||||
|
||||
print("get_custom_panels:")
|
||||
panels = [
|
||||
{
|
||||
# This 'hello world' panel will be displayed on any view which implements custom panels
|
||||
'title': 'Hello World',
|
||||
'icon': 'fas fa-boxes',
|
||||
'content': '<b>Hello world!</b>',
|
||||
'description': 'A simple panel which renders hello world',
|
||||
'javascript': 'alert("Hello world");',
|
||||
},
|
||||
{
|
||||
# This panel will not be displayed, as it is missing the 'content' key
|
||||
'title': 'No Content',
|
||||
}
|
||||
]
|
||||
|
||||
return []
|
||||
# This panel will *only* display on the PartDetail view
|
||||
if isinstance(view, PartDetail):
|
||||
panels.append({
|
||||
'title': 'Custom Part Panel',
|
||||
'icon': 'fas fa-shapes',
|
||||
'content': '<em>This content only appears on the PartDetail page, you know!</em>',
|
||||
})
|
||||
|
||||
# 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()
|
||||
|
||||
if not loc.get_descendants(include_self=False).exists():
|
||||
panels.append({
|
||||
'title': 'Childless',
|
||||
'icon': 'fa-user',
|
||||
'content': '<h4>I have no children!</h4>'
|
||||
})
|
||||
else:
|
||||
print("abcdefgh")
|
||||
|
||||
except:
|
||||
print("error could not get object!")
|
||||
pass
|
||||
|
||||
return panels
|
||||
|
Loading…
Reference in New Issue
Block a user