mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 01:06:11 -06:00
12591 restore view
This commit is contained in:
parent
cd5f3cc318
commit
68341c55b3
@ -31,11 +31,20 @@ IMAGEATTACHMENT_IMAGE = '''
|
||||
{% endif %}
|
||||
'''
|
||||
|
||||
REVISION_BUTTONS = """
|
||||
{% if not record.is_active %}
|
||||
<a href="{% url 'extras:configrevision_restore' pk=record.pk %}" class="btn btn-sm btn-primary" title="Restore config">
|
||||
<i class="mdi mdi-file-restore"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
|
||||
class ConfigRevisionTable(NetBoxTable):
|
||||
is_active = columns.BooleanColumn()
|
||||
actions = columns.ActionsColumn(
|
||||
actions=('edit', 'delete'),
|
||||
extra_buttons=REVISION_BUTTONS
|
||||
)
|
||||
|
||||
class Meta(NetBoxTable.Meta):
|
||||
|
@ -120,5 +120,6 @@ urlpatterns = [
|
||||
path('config-revision/', views.ConfigRevisionListView.as_view(), name='configrevision'),
|
||||
path('config-revision/add/', views.ConfigRevisionEditView.as_view(), name='configrevision_add'),
|
||||
path('config-revision/delete/', views.ConfigRevisionBulkDeleteView.as_view(), name='configrevision_bulk_delete'),
|
||||
path('config-revision/<int:pk>/restore', views.ConfigRevisionRestoreView.as_view(), name='configrevision_restore'),
|
||||
path('config-revision/<int:pk>/', include(get_model_urls('extras', 'configrevision'))),
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ from core.models import Job
|
||||
from core.tables import JobTable
|
||||
from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm
|
||||
from extras.dashboard.utils import get_widget_class
|
||||
from netbox.config import get_config, PARAMS
|
||||
from netbox.views import generic
|
||||
from utilities.forms import ConfirmationForm, get_field_value
|
||||
from utilities.htmx import is_htmx
|
||||
@ -1223,3 +1224,39 @@ class ConfigRevisionBulkDeleteView(generic.BulkDeleteView):
|
||||
queryset = ConfigRevision.objects.all()
|
||||
filterset = filtersets.ConfigRevisionFilterSet
|
||||
table = tables.ConfigRevisionTable
|
||||
|
||||
|
||||
class ConfigRevisionRestoreView(ContentTypePermissionRequiredMixin, View):
|
||||
|
||||
def get_required_permission(self):
|
||||
return 'extras.configrevision_edit'
|
||||
|
||||
def get(self, request, pk):
|
||||
candidate_config = get_object_or_404(ConfigRevision, pk=pk)
|
||||
|
||||
# Get the current ConfigRevision
|
||||
config_version = get_config().version
|
||||
current_config = ConfigRevision.objects.filter(pk=config_version).first()
|
||||
|
||||
params = []
|
||||
for param in PARAMS:
|
||||
params.append((
|
||||
param.name,
|
||||
current_config.data.get(param.name, None),
|
||||
candidate_config.data.get(param.name, None)
|
||||
))
|
||||
|
||||
return render(request, 'extras/configrevision_restore.html', {
|
||||
'object': candidate_config,
|
||||
'params': params,
|
||||
})
|
||||
|
||||
def post(self, request, pk):
|
||||
if not request.user.has_perm('extras.configrevision_edit'):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
candidate_config = get_object_or_404(ConfigRevision, pk=pk)
|
||||
candidate_config.activate()
|
||||
self.message_user(request, f"Restored configuration revision #{pk}")
|
||||
|
||||
return redirect(reverse('admin:extras_configrevision_changelist'))
|
||||
|
75
netbox/templates/extras/configrevision_restore.html
Normal file
75
netbox/templates/extras/configrevision_restore.html
Normal file
@ -0,0 +1,75 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
{% load helpers %}
|
||||
{% load buttons %}
|
||||
{% load perms %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{ script }}{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{{ script.Meta.description|markdown }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<div class="row noprint">
|
||||
<div class="col col-md-12">
|
||||
<nav class="breadcrumb-container px-3" aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'extras:script_list' %}">Scripts</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
{{ block.super }}
|
||||
{% endblock header %}
|
||||
|
||||
{% block controls %}
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
{% if request.user|can_delete:job %}
|
||||
{% delete_button job %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock controls %}
|
||||
|
||||
{% block content %}
|
||||
<ul class="nav nav-tabs px-3" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href="#log" role="tab" data-bs-toggle="tab" class="nav-link active">Log</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content mb-3">
|
||||
<div role="tabpanel" class="tab-pane active" id="log">
|
||||
<div class="row">
|
||||
|
||||
<p>Restore configuration #{{ object.pk }} from <strong>{{ object.created }}</strong>?</p>
|
||||
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Parameter</th>
|
||||
<th scope="col">Current Value</th>
|
||||
<th scope="col">New Value</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for param, current, new in params %}
|
||||
<tr{% if current != new %} class="table-warning"{% endif %}>
|
||||
<td>{{ param }}</td>
|
||||
<td>{{ current }}</td>
|
||||
<td>{{ new }}</td>
|
||||
<td>{% if current != new %}<img src="{% static 'admin/img/icon-changelink.svg' %}" alt="*" title="Changed">{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{% endblock modals %}
|
Loading…
Reference in New Issue
Block a user