Replace clone_button with an ObjectAction

This commit is contained in:
Jeremy Stretch 2025-06-30 10:37:25 -04:00
parent 12739ec31c
commit 2b68841f31
4 changed files with 45 additions and 24 deletions

View File

@ -3,6 +3,7 @@ from django.utils.translation import gettext as _
from core.models import ObjectType
from extras.models import ExportTemplate
from utilities.querydict import prepare_cloned_fields
__all__ = (
'AddObject',
@ -11,6 +12,7 @@ __all__ = (
'BulkExport',
'BulkImport',
'BulkRename',
'CloneObject',
'DeleteObject',
'EditObject',
'ObjectAction',
@ -22,7 +24,7 @@ class ObjectAction:
Base class for single- and multi-object operations.
Params:
name: The action name
name: The action name appended to the module for view resolution
label: Human-friendly label for the rendered button
multi: Set to True if this action is performed by selecting multiple objects (i.e. using a table)
permissions_required: The set of permissions a user must have to perform the action
@ -60,6 +62,25 @@ class AddObject(ObjectAction):
template_name = 'buttons/add.html'
class CloneObject(ObjectAction):
"""
Populate the new object form with select details from an existing object.
"""
name = 'add'
label = _('Clone')
permissions_required = {'add'}
template_name = 'buttons/clone.html'
@classmethod
def get_context(cls, context, obj):
param_string = prepare_cloned_fields(obj).urlencode()
url = f'{cls.get_url(obj)}?{param_string}' if param_string else None
return {
'url': url,
'label': cls.label,
}
class EditObject(ObjectAction):
"""
Edit a single object.

View File

@ -14,7 +14,9 @@ from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from core.signals import clear_events
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, DeleteObject, EditObject
from netbox.object_actions import (
AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, CloneObject, DeleteObject, EditObject,
)
from utilities.error_handlers import handle_protectederror
from utilities.exceptions import AbortRequest, PermissionsViolation
from utilities.forms import ConfirmationForm, restrict_form_fields
@ -47,7 +49,7 @@ class ObjectView(ActionsMixin, BaseObjectView):
tab: A ViewTab instance for the view
"""
tab = None
actions = (EditObject, DeleteObject)
actions = (CloneObject, EditObject, DeleteObject)
def get_required_permission(self):
return get_permission_for_model(self.queryset.model, 'view')

View File

@ -80,9 +80,6 @@ Context:
{% if perms.extras.add_subscription and object.subscriptions %}
{% subscribe_button object %}
{% endif %}
{% if request.user|can_add:object %}
{% clone_button object %}
{% endif %}
{% action_buttons actions object %}
{% endblock control-buttons %}
</div>

View File

@ -69,24 +69,6 @@ def bookmark_button(context, instance):
}
@register.inclusion_tag('buttons/clone.html')
def clone_button(instance):
# Resolve URL path
viewname = get_viewname(instance, 'add')
try:
url = reverse(viewname)
except NoReverseMatch:
return {
'url': None,
}
# Populate cloned field values and return full URL
param_string = prepare_cloned_fields(instance).urlencode()
return {
'url': f'{url}?{param_string}' if param_string else None,
}
@register.inclusion_tag('buttons/subscribe.html', takes_context=True)
def subscribe_button(context, instance):
# Skip for objects which don't support notifications
@ -126,6 +108,25 @@ def subscribe_button(context, instance):
# Legacy object buttons
#
# TODO: Remove in NetBox v4.6
@register.inclusion_tag('buttons/clone.html')
def clone_button(instance):
# Resolve URL path
viewname = get_viewname(instance, 'add')
try:
url = reverse(viewname)
except NoReverseMatch:
return {
'url': None,
}
# Populate cloned field values and return full URL
param_string = prepare_cloned_fields(instance).urlencode()
return {
'url': f'{url}?{param_string}' if param_string else None,
}
# TODO: Remove in NetBox v4.6
@register.inclusion_tag('buttons/edit.html')
def edit_button(instance):