From 70e5c7b14231d718bb657b0c957a6124e0821d80 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@gmail.com>
Date: Fri, 14 Jun 2024 13:59:09 +0000
Subject: [PATCH] Adds basic API endpoint for requesting plugin panels

---
 src/backend/InvenTree/InvenTree/urls.py     |  2 +-
 src/backend/InvenTree/plugin/api.py         | 25 +++++++++++++++++++++
 src/backend/InvenTree/plugin/serializers.py | 14 ++++++++++++
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/backend/InvenTree/InvenTree/urls.py b/src/backend/InvenTree/InvenTree/urls.py
index e9cd4ead4c..81716ea3dd 100644
--- a/src/backend/InvenTree/InvenTree/urls.py
+++ b/src/backend/InvenTree/InvenTree/urls.py
@@ -480,7 +480,7 @@ if settings.ENABLE_PLATFORM_FRONTEND:
 
 urlpatterns += frontendpatterns
 
-# Append custom plugin URLs (if plugin support is enabled)
+# Append custom plugin URLs (if custom plugin support is enabled)
 if settings.PLUGINS_ENABLED:
     urlpatterns.append(get_plugin_urls())
 
diff --git a/src/backend/InvenTree/plugin/api.py b/src/backend/InvenTree/plugin/api.py
index df1877bf56..79840c3f23 100644
--- a/src/backend/InvenTree/plugin/api.py
+++ b/src/backend/InvenTree/plugin/api.py
@@ -9,6 +9,7 @@ from django_filters.rest_framework import DjangoFilterBackend
 from drf_spectacular.utils import extend_schema
 from rest_framework import permissions, status
 from rest_framework.exceptions import NotFound
+from rest_framework.permissions import IsAuthenticated
 from rest_framework.response import Response
 from rest_framework.views import APIView
 
@@ -410,6 +411,24 @@ class RegistryStatusView(APIView):
         return Response(result)
 
 
+class PluginPanelList(APIView):
+    """API endpoint for listing all available plugin panels."""
+
+    permission_classes = [IsAuthenticated]
+    serializer_class = PluginSerializers.PluginPanelSerializer
+
+    @extend_schema(responses={200: PluginSerializers.PluginPanelSerializer(many=True)})
+    def get(self, request):
+        """Show available plugin panels."""
+        panels = []
+
+        # Extract all plugins from the registry which provide custom panels
+        for _plugin in registry.with_mixin('panel', active=True):
+            ...
+
+        return Response(PluginSerializers.PluginPanelSerializer(panels, many=True).data)
+
+
 plugin_api_urls = [
     path('action/', ActionPluginView.as_view(), name='api-action-plugin'),
     path('barcode/', include(barcode_api_urls)),
@@ -417,6 +436,12 @@ plugin_api_urls = [
     path(
         'plugins/',
         include([
+            path(
+                'panel/',
+                include([
+                    path('', PluginPanelList.as_view(), name='api-plugin-panel-list')
+                ]),
+            ),
             # Plugin management
             path('reload/', PluginReload.as_view(), name='api-plugin-reload'),
             path('install/', PluginInstall.as_view(), name='api-plugin-install'),
diff --git a/src/backend/InvenTree/plugin/serializers.py b/src/backend/InvenTree/plugin/serializers.py
index 30fd5325ee..968e06728d 100644
--- a/src/backend/InvenTree/plugin/serializers.py
+++ b/src/backend/InvenTree/plugin/serializers.py
@@ -303,3 +303,17 @@ class PluginRelationSerializer(serializers.PrimaryKeyRelatedField):
     def to_representation(self, value):
         """Return the 'key' of the PluginConfig object."""
         return value.key
+
+
+class PluginPanelSerializer(serializers.Serializer):
+    """Serializer for a plugin panel."""
+
+    class Meta:
+        """Meta for serializer."""
+
+        fields = ['plugin', 'title', 'description', 'icon']
+
+    plugin = serializers.CharField(label=_('Plugin Key'))
+    title = serializers.CharField(label=_('Panel Title'))
+    description = serializers.CharField(label=_('Panel Description'))
+    icon = serializers.CharField(label=_('Panel Icon'))