2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-05-22 01:06:50 +00:00

feat(frontend): Add option for plugins to add header actions (#9570)

* [FR] PUI - Add option for plugins to add header actions
Fixes #8593

* fix parsing

* fix merge

* reduce diff

* fix sample implementation

* add support for icons and colors in primary actions

* add changelog entry

* add docs

* add more detailed sample text

* pass location into context

* fix test

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
Matthias Mair
2026-05-22 00:20:07 +02:00
committed by GitHub
parent 65d15a5945
commit f27b9b5443
10 changed files with 122 additions and 10 deletions
@@ -21,6 +21,7 @@ FeatureType = Literal[
'template_editor', # Custom template editor
'template_preview', # Custom template preview
'navigation', # Custom navigation items
'primary_action', # Custom primary action buttons
]
@@ -106,6 +107,7 @@ class UserInterfaceMixin:
'panel': self.get_ui_panels,
'template_editor': self.get_ui_template_editors,
'template_preview': self.get_ui_template_previews,
'primary_action': self.get_ui_primary_actions,
}
if feature_type in feature_map:
@@ -203,3 +205,29 @@ class UserInterfaceMixin:
"""
# Default implementation returns an empty list
return []
def get_ui_primary_actions(
self, request: Request, context: dict, **kwargs
) -> list[UIFeature]:
"""Return a list of custom primary action buttons to be injected into the UI.
Args:
request: HTTPRequest object (including user information)
context: Additional context data provided by the UI (query parameters)
Returns:
list: A list of custom primary action buttons to be injected into the UI
"""
# Sample code to render conditional primary action button based on context
# items = []
# if self.my_assert_function(context):
# items.append({
# 'key': 'sample-primary-action',
# 'title': 'Sample Primary Action',
# 'icon': 'ti:plus:outline',
# 'options': {'url': '/core/sample-primary-action/', 'color': 'orange'},
# })
# return items
# Default implementation returns an empty list
return []
@@ -233,3 +233,13 @@ class UserInterfaceMixinTests(InvenTreeAPITestCase):
self.assertEqual(response.data[0]['plugin_name'], 'sampleui')
self.assertEqual(response.data[0]['key'], 'sample-nav-item')
self.assertEqual(response.data[0]['title'], 'Sample Nav Item')
def test_ui_primary_actions(self):
"""Test that the sample UI plugin provides custom primary actions."""
response = self.get(
reverse('api-plugin-ui-feature-list', kwargs={'feature': 'primary_action'})
)
self.assertEqual(1, len(response.data))
self.assertEqual(response.data[0]['plugin_name'], 'sampleui')
self.assertEqual(response.data[0]['key'], 'sample-primary-action')
self.assertEqual(response.data[0]['title'], 'Sample Primary Action')
@@ -226,6 +226,17 @@ class SampleUserInterfacePlugin(SettingsMixin, UserInterfaceMixin, InvenTreePlug
}
]
def get_ui_primary_actions(self, request, context, **kwargs):
"""Return a list of custom primary action buttons."""
return [
{
'key': 'sample-primary-action',
'title': 'Sample Primary Action',
'icon': 'ti:plus:outline',
'options': {'url': '/core/sample-primary-action/', 'color': 'orange'},
}
]
def get_admin_context(self) -> dict:
"""Return custom context data which can be rendered in the admin panel."""
return {'apple': 'banana', 'foo': 'bar', 'hello': 'world'}