add "Manage Router Groups" feature with UI, actions for adding/removing routers from groups, and integration into router list

This commit is contained in:
Eduardo Silva 2025-06-17 15:21:09 -03:00
parent 6f9bc5d41c
commit 763f6cb99a
4 changed files with 152 additions and 1 deletions

View file

@ -301,6 +301,67 @@ def view_create_instant_backup_multiple_routers(request):
return JsonResponse({'error': 'Invalid request method.'}, status=405)
@login_required
def view_manage_router_groups_multiple(request):
if not UserAcl.objects.filter(user=request.user, user_level__gte=20).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
if request.method == 'POST':
router_uuids = request.POST.getlist('router_uuids')
add_group_uuid = request.POST.get('add_group')
remove_group_uuid = request.POST.get('remove_group')
if not router_uuids:
messages.warning(request, 'No routers selected')
return redirect('router_list')
# Validate that the same group is not selected for both add and remove
if add_group_uuid and remove_group_uuid and add_group_uuid == remove_group_uuid:
messages.warning(request, 'Cannot add and remove from the same group')
return redirect('router_list')
routers = Router.objects.filter(uuid__in=router_uuids)
# Process add to group
if add_group_uuid:
try:
group = RouterGroup.objects.get(uuid=add_group_uuid)
for router in routers:
group.routers.add(router)
messages.success(request, f'Added {routers.count()} router(s) to group {group.name}')
except RouterGroup.DoesNotExist:
messages.error(request, 'Group not found')
# Process remove from group
if remove_group_uuid:
try:
group = RouterGroup.objects.get(uuid=remove_group_uuid)
for router in routers:
group.routers.remove(router)
messages.success(request, f'Removed {routers.count()} router(s) from group {group.name}')
except RouterGroup.DoesNotExist:
messages.error(request, 'Group not found')
return redirect('router_list')
# GET request - display form
router_uuids = request.GET.getlist('routers[]')
if not router_uuids:
messages.warning(request, 'No routers selected')
return redirect('router_list')
routers = Router.objects.filter(uuid__in=router_uuids)
groups = RouterGroup.objects.all().order_by('name')
context = {
'routers': routers,
'groups': groups,
'page_title': 'Manage Router Groups',
}
return render(request, 'router_manager/manage_router_groups.html', context)
def view_cron_update_router_information(request):
data = {'status': 'success'}
refresh_interval = 24 #hours

View file

@ -6,7 +6,7 @@ from dashboard.views import view_dashboard, view_status,backup_statistics_data,r
from integration_manager.views import view_wireguard_webadmin_launcher, view_manage_wireguard_integration, view_launch_wireguard_webadmin
from user_manager.views import view_manage_user, view_user_list
from accounts.views import view_login, view_logout, view_create_first_user
from router_manager.views import view_create_instant_backup_multiple_routers, view_router_list, view_manage_router, view_router_group_list, view_ssh_key_list, view_manage_router_group, view_manage_sshkey, view_router_details, view_create_instant_backup_task, view_router_availability, view_cron_update_router_information
from router_manager.views import view_create_instant_backup_multiple_routers, view_router_list, view_manage_router, view_router_group_list, view_ssh_key_list, view_manage_router_group, view_manage_sshkey, view_router_details, view_create_instant_backup_task, view_router_availability, view_cron_update_router_information, view_manage_router_groups_multiple
from backup.views import view_backup_profile_list, view_manage_backup_profile, view_backup_list, view_backup_details, view_debug_run_backups, view_compare_backups, view_backup_download, view_backup_delete
from monitoring.views import view_export_router_list, view_update_router_status, view_router_config_timestamp, view_router_last_status_change
from backup_data.views import view_generate_backup_schedule, view_create_backup_tasks, view_perform_backup_tasks, view_housekeeping
@ -38,6 +38,7 @@ urlpatterns = [
path('router/manage_sshkey/', view_manage_sshkey, name='manage_sshkey'),
path('router/create_instant_backup/', view_create_instant_backup_task, name='create_instant_backup_task'),
path('router/create_instant_backup/multiple/', view_create_instant_backup_multiple_routers, name='create_instant_backup_multiple'),
path('router/manage_groups/multiple/', view_manage_router_groups_multiple, name='manage_router_groups_multiple'),
path('router/import_tool/', view_import_tool_list, name='import_tool_list'),
path('router/import_tool/csv/', view_import_csv_file, name='import_csv_file'),
path('router/import_tool/details/', view_import_details, name='import_details'),

View file

@ -0,0 +1,76 @@
{% extends 'base.html' %}
{% block content %}
<div class='row'>
<div class='col-lg-6'>
<div class="card card-primary card-outline">
<div class="card-header">
<h3 class="card-title">Manage Router Groups</h3>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-12">
<h4>Selected Routers:</h4>
<ul>
{% for router in routers %}
<li>{{ router.name }}</li>
<input type="hidden" name="router_uuids" value="{{ router.uuid }}">
{% endfor %}
</ul>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="add_group">Add to Group:</label>
<select class="form-control" id="add_group" name="add_group">
<option value="">-- Select Group --</option>
{% for group in groups %}
<option value="{{ group.uuid }}">{{ group.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="remove_group">Remove from Group:</label>
<select class="form-control" id="remove_group" name="remove_group">
<option value="">-- Select Group --</option>
{% for group in groups %}
<option value="{{ group.uuid }}">{{ group.name }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-success">Apply Changes</button>
<a href="/router/list/" class="btn btn-secondary">Cancel</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_page_scripts %}
<script>
$(document).ready(function() {
// Prevent selecting the same group for both add and remove
$('#add_group, #remove_group').on('change', function() {
var addGroup = $('#add_group').val();
var removeGroup = $('#remove_group').val();
if (addGroup && removeGroup && addGroup === removeGroup) {
alert("You cannot select the same group for both adding and removing.");
$(this).val('');
}
});
});
</script>
{% endblock %}

View file

@ -260,6 +260,7 @@
<button id="select-all" class="btn btn-outline-primary" title="Select All"><i class="fas fa-check-square"></i></button>
<button id="select-none" class="btn btn-outline-primary" title="Select None"><i class="fas fa-square"></i></button>
<button id="create-backup" class="btn btn-warning" style="display: none;">Create Backup Task</button>
<button id="manage-groups" class="btn btn-primary" style="display: none;">Groups</button>
</div>
</div>
</div>
@ -478,8 +479,10 @@ $(document).ready(function() {
var checkedCount = table.$('.router-checkbox:checked').length;
if (checkedCount >= 1) {
$('#create-backup').show();
$('#manage-groups').show();
} else {
$('#create-backup').hide();
$('#manage-groups').hide();
}
});
@ -542,6 +545,16 @@ $(document).ready(function() {
}
});
});
$('#manage-groups').on('click', function(e) {
e.preventDefault();
var selectedRouters = table.$('.router-checkbox:checked').map(function() {
return $(this).data('uuid');
}).get();
// Redirect to the manage groups page with the selected routers
window.location.href = '/router/manage_groups/multiple/?routers[]=' + selectedRouters.join('&routers[]=');
});
});
</script>