feat: add plugin support for custom page integration (#12900)

* Added plugin UI route functionality.

* Updated Sample UI plugin with route example.

* Added UI route tests.

* Plugin name added to UI Route URL.

* Updated docs.

* Docs fix.

* Updated sample_route text.

* Update src/backend/InvenTree/plugin/base/ui/mixins.py

Co-authored-by: Matthias Mair <code@mjmair.com>

* Fixed nav dynamic link highlighting.

* Added changelog entry.

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
James Todd
2026-09-27 08:13:54 +10:00
committed by GitHub
co-authored by Matthias Mair Oliver
parent ba848a83aa
commit d33d77d679
11 changed files with 199 additions and 5 deletions
+34
View File
@@ -197,6 +197,40 @@ The `get_ui_primary_actions` method can be used to provide custom primary action
summary: False
members: []
### Routes
The `get_ui_routes` method can be used to provide custom routes (and therefore pages) within the InvenTree web interface.
::: plugin.base.ui.mixins.UserInterfaceMixin.get_ui_routes
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
summary: False
members: []
extra:
show_source: True
A route is defined by returning a list of route definitions:
```python
def get_ui_routes(self, request, context, **kwargs):
return [
{
'key': 'my-plugin-page',
'title': 'My Plugin Page',
'source': self.plugin_static_file('my_page.js:getFeature'),
'options': {
'path': 'page/:pk',
},
},
]
```
Routes are exposed below `/web/plugin/<plugin-name>/`. For example, the route above would be available at: `/web/plugin/my-plugin/page/<pk>`
The path is relative to the plugin's own URL namespace and uses React Router path syntax, so parameters can be specified using :parameter notation.
## Plugin Context
When rendering certain content in the user interface, the rendering functions are passed a `context` object which contains information about the current page being rendered. The type of the `context` object is defined in the `PluginContext` file: