Repository: nautobot/nautobot

Issue:
Ability to register additional method to a UI Viewset via NautobotUIViewSetRouter
### As ...

P.D. - Plugin Developer

### I want ...

The ability to define additional routes as part of a single viewset for a given model

### So that ...

I can build one call to handle all out of the box views plus any additional non-standard views.

### I know this is done when...

- I create a new model in a plugin that requires N non-standard views and each non-standard view does NOT require an additional URL pattern to be registered.
- 

### Optional - Feature groups this request pertains to.

- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [ ] Misc (including Data Sources)
- [ ] Organization
- [X] Plugins (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [ ] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)

### Database Changes

None

### External Dependencies

None


Discussion:

Resolving patch:
diff --git a/nautobot/core/views/mixins.py b/nautobot/core/views/mixins.py
--- a/nautobot/core/views/mixins.py
+++ b/nautobot/core/views/mixins.py
@@ -20,6 +20,7 @@
 from django.views.generic.edit import FormView
 
 from rest_framework import mixins, exceptions
+from rest_framework.decorators import action as drf_action
 from rest_framework.parsers import FormParser, MultiPartParser
 from rest_framework.response import Response
 from rest_framework.viewsets import GenericViewSet
@@ -957,6 +958,7 @@ class ObjectChangeLogViewMixin(NautobotViewSetMixin):
 
     base_template = None
 
+    @drf_action(detail=True)
     def changelog(self, request, *args, **kwargs):
         data = {
             "base_template": self.base_template,
@@ -971,6 +973,7 @@ class ObjectNotesViewMixin(NautobotViewSetMixin):
 
     base_template = None
 
+    @drf_action(detail=True)
     def notes(self, request, *args, **kwargs):
         data = {
             "base_template": self.base_template,
diff --git a/nautobot/core/views/routers.py b/nautobot/core/views/routers.py
--- a/nautobot/core/views/routers.py
+++ b/nautobot/core/views/routers.py
@@ -1,4 +1,4 @@
-from rest_framework.routers import Route, SimpleRouter
+from rest_framework.routers import DynamicRoute, Route, SimpleRouter
 
 
 class NautobotUIViewSetRouter(SimpleRouter):
@@ -79,22 +79,11 @@ class NautobotUIViewSetRouter(SimpleRouter):
             detail=True,
             initkwargs={"suffix": "Edit"},
         ),
-        Route(
-            url=r"^{prefix}/{lookup}/changelog/$",
-            mapping={
-                "get": "changelog",
-            },
-            name="{basename}_changelog",
-            detail=True,
-            initkwargs={"suffix": "Changelog"},
-        ),
-        Route(
-            url=r"^{prefix}/{lookup}/notes/$",
-            mapping={
-                "get": "notes",
-            },
-            name="{basename}_notes",
+        # DynamicRoute will handle ChangeLog & Notes UI Views
+        DynamicRoute(
+            url=r"^{prefix}/{lookup}/{url_path}{trailing_slash}$",
+            name="{basename}_{url_name}",
             detail=True,
-            initkwargs={"suffix": "Notes"},
+            initkwargs={},
         ),
     ]


Test patch: