mirror of
https://github.com/eduardogsilva/routerfleet.git
synced 2025-07-10 02:04:24 +02:00
router manager navigation and form validation improvements
This commit is contained in:
parent
2a95f0c77f
commit
a8952676d7
13 changed files with 491 additions and 30 deletions
|
@ -1,10 +1,14 @@
|
|||
from django import forms
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout, Submit, Row, Column, HTML
|
||||
from .models import Router
|
||||
from .models import Router, RouterGroup, SSHKey
|
||||
import ipaddress
|
||||
import socket
|
||||
|
||||
|
||||
class RouterForm(forms.ModelForm):
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Router
|
||||
fields = ['name', 'address', 'username', 'password', 'ssh_key', 'monitoring', 'router_type', 'enabled']
|
||||
|
@ -15,6 +19,8 @@ class RouterForm(forms.ModelForm):
|
|||
self.helper.form_method = 'post'
|
||||
if self.instance.pk:
|
||||
delete_html = "<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>Delete</a>"
|
||||
if self.instance.password:
|
||||
self.fields['password'].widget.attrs['placeholder'] = '************'
|
||||
else:
|
||||
delete_html = ''
|
||||
self.helper.layout = Layout(
|
||||
|
@ -29,7 +35,6 @@ class RouterForm(forms.ModelForm):
|
|||
css_class='form-row'
|
||||
),
|
||||
'ssh_key',
|
||||
|
||||
'router_type',
|
||||
'monitoring',
|
||||
'enabled',
|
||||
|
@ -42,3 +47,121 @@ class RouterForm(forms.ModelForm):
|
|||
css_class='form-row'
|
||||
)
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
name = cleaned_data.get('name')
|
||||
ssh_key = cleaned_data.get('ssh_key')
|
||||
password = cleaned_data.get('password')
|
||||
address = cleaned_data.get('address')
|
||||
|
||||
if name:
|
||||
name = name.strip()
|
||||
cleaned_data['name'] = name
|
||||
|
||||
if ssh_key and password:
|
||||
raise forms.ValidationError('You must provide a password or an SSH Key, not both')
|
||||
if not ssh_key and not password and not self.instance.password:
|
||||
raise forms.ValidationError('You must provide a password or an SSH Key')
|
||||
|
||||
if not password and self.instance.password:
|
||||
cleaned_data['password'] = self.instance.password
|
||||
|
||||
if ssh_key and not password:
|
||||
cleaned_data['password'] = ''
|
||||
|
||||
if address:
|
||||
address = address.lower()
|
||||
cleaned_data['address'] = address
|
||||
|
||||
try:
|
||||
socket.gethostbyname(address)
|
||||
except socket.gaierror:
|
||||
try:
|
||||
ipaddress.ip_address(address)
|
||||
except ValueError:
|
||||
raise forms.ValidationError('The address field must be a valid hostname or IP address.')
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class RouterGroupForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = RouterGroup
|
||||
fields = ['name', 'default_group', 'internal_notes', 'routers']
|
||||
widgets = {
|
||||
'internal_notes': forms.Textarea(attrs={'rows': 4, 'cols': 40}), # Define como um Textarea simples
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RouterGroupForm, self).__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
if self.instance.pk:
|
||||
delete_html = "<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>Delete</a>"
|
||||
else:
|
||||
delete_html = ''
|
||||
self.helper.layout = Layout(
|
||||
'name',
|
||||
'internal_notes',
|
||||
'routers',
|
||||
'default_group',
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', 'Salvar', css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/router/group_list/">Back</a> '),
|
||||
HTML(delete_html),
|
||||
css_class='col-md-12'),
|
||||
css_class='form-row'
|
||||
)
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
name = cleaned_data.get('name')
|
||||
default_group = cleaned_data.get('default_group')
|
||||
|
||||
if name:
|
||||
name = name.strip()
|
||||
cleaned_data['name'] = name
|
||||
|
||||
if default_group:
|
||||
RouterGroup.objects.filter(default_group=True).update(default_group=False)
|
||||
return cleaned_data
|
||||
|
||||
class SSHKeyForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SSHKey
|
||||
fields = ['name', 'public_key', 'private_key']
|
||||
widgets = {
|
||||
'public_key': forms.Textarea(attrs={'rows': 4, 'cols': 40}),
|
||||
'private_key': forms.Textarea(attrs={'rows': 4, 'cols': 40}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SSHKeyForm, self).__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
if self.instance.pk:
|
||||
delete_html = "<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>Delete</a>"
|
||||
else:
|
||||
delete_html = ''
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column('name', css_class='form-group col-md-12 mb-0'),
|
||||
),
|
||||
Row(
|
||||
Column('public_key', css_class='form-group col-md-12 mb-0'),
|
||||
),
|
||||
Row(
|
||||
Column('private_key', css_class='form-group col-md-12 mb-0'),
|
||||
),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', 'Salvar', css_class='btn btn-success'),
|
||||
HTML(' <a class="btn btn-secondary" href="/router/ssh_keys/">Back</a> '),
|
||||
HTML(delete_html),
|
||||
css_class='col-md-12'),
|
||||
css_class='form-row'
|
||||
)
|
||||
)
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 5.0.3 on 2024-03-16 18:27
|
||||
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0003_routerstatus'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='router',
|
||||
name='internal_notes',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='router',
|
||||
name='name',
|
||||
field=models.CharField(max_length=100, unique=True),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RouterGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, unique=True)),
|
||||
('internal_notes', models.TextField(blank=True, null=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
('routers', models.ManyToManyField(to='router_manager.router')),
|
||||
],
|
||||
),
|
||||
]
|
18
router_manager/migrations/0005_alter_sshkey_name.py
Normal file
18
router_manager/migrations/0005_alter_sshkey_name.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-03-16 18:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0004_router_internal_notes_alter_router_name_routergroup'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='sshkey',
|
||||
name='name',
|
||||
field=models.CharField(max_length=100, unique=True),
|
||||
),
|
||||
]
|
18
router_manager/migrations/0006_routergroup_default_group.py
Normal file
18
router_manager/migrations/0006_routergroup_default_group.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-03-16 19:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0005_alter_sshkey_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='routergroup',
|
||||
name='default_group',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
18
router_manager/migrations/0007_alter_routergroup_routers.py
Normal file
18
router_manager/migrations/0007_alter_routergroup_routers.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-03-16 20:22
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0006_routergroup_default_group'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='routergroup',
|
||||
name='routers',
|
||||
field=models.ManyToManyField(blank=True, to='router_manager.router'),
|
||||
),
|
||||
]
|
|
@ -3,7 +3,7 @@ import uuid
|
|||
|
||||
|
||||
class SSHKey(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
public_key = models.TextField()
|
||||
private_key = models.TextField()
|
||||
|
||||
|
@ -16,7 +16,8 @@ class SSHKey(models.Model):
|
|||
|
||||
|
||||
class Router(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
internal_notes = models.TextField(null=True, blank=True)
|
||||
address = models.CharField(max_length=15)
|
||||
username = models.CharField(max_length=100, default='admin')
|
||||
password = models.CharField(max_length=100, null=True, blank=True)
|
||||
|
@ -44,3 +45,16 @@ class RouterStatus(models.Model):
|
|||
created = models.DateTimeField(auto_now_add=True)
|
||||
uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
|
||||
|
||||
|
||||
class RouterGroup(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
default_group = models.BooleanField(default=False)
|
||||
internal_notes = models.TextField(null=True, blank=True)
|
||||
routers = models.ManyToManyField(Router, blank=True)
|
||||
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -1,17 +1,28 @@
|
|||
from django.contrib import messages
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from .models import Router
|
||||
from .forms import RouterForm
|
||||
from .models import Router, RouterGroup, RouterStatus, SSHKey
|
||||
from .forms import RouterForm, RouterGroupForm, SSHKeyForm
|
||||
|
||||
|
||||
@login_required
|
||||
def view_router_list(request):
|
||||
router_list = Router.objects.all()
|
||||
router_list = Router.objects.all().order_by('name')
|
||||
filter_group = None
|
||||
if request.GET.get('filter_group'):
|
||||
if request.GET.get('filter_group') == 'all':
|
||||
pass
|
||||
else:
|
||||
filter_group = get_object_or_404(RouterGroup, uuid=request.GET.get('filter_group'))
|
||||
router_list = router_list.filter(routergroup=filter_group)
|
||||
|
||||
if not filter_group and request.GET.get('filter_group') != 'all':
|
||||
filter_group = RouterGroup.objects.filter(default_group=True).first()
|
||||
context = {
|
||||
'router_list': router_list,
|
||||
'page_title': 'Router List',
|
||||
|
||||
'filter_group_list': RouterGroup.objects.all().order_by('name'),
|
||||
'filter_group': filter_group,
|
||||
}
|
||||
return render(request, 'router_manager/router_list.html', context=context)
|
||||
|
||||
|
@ -43,3 +54,79 @@ def view_manage_router(request):
|
|||
'instance': router
|
||||
}
|
||||
return render(request, 'generic_form.html', context=context)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_router_group_list(request):
|
||||
context = {
|
||||
'router_group_list': RouterGroup.objects.all().order_by('name'),
|
||||
'page_title': 'Router Group List',
|
||||
}
|
||||
return render(request, 'router_manager/router_group_list.html', context=context)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_manage_router_group(request):
|
||||
if request.GET.get('uuid'):
|
||||
router_group = get_object_or_404(RouterGroup, uuid=request.GET.get('uuid'))
|
||||
if request.GET.get('action') == 'delete':
|
||||
if request.GET.get('confirmation') == 'delete':
|
||||
router_group.delete()
|
||||
messages.success(request, 'Router Group deleted successfully')
|
||||
return redirect('router_group_list')
|
||||
else:
|
||||
messages.warning(request, 'Router Group not deleted|Invalid confirmation')
|
||||
return redirect('router_group_list')
|
||||
else:
|
||||
router_group = None
|
||||
|
||||
form = RouterGroupForm(request.POST or None, instance=router_group)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, 'Router Group saved successfully')
|
||||
return redirect('router_group_list')
|
||||
|
||||
context = {
|
||||
'form': form,
|
||||
'page_title': 'Manage Router Group',
|
||||
'instance': router_group
|
||||
}
|
||||
return render(request, 'generic_form.html', context=context)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_ssh_key_list(request):
|
||||
context = {
|
||||
'sshkey_list': SSHKey.objects.all().order_by('name'),
|
||||
'page_title': 'SSH Key List',
|
||||
}
|
||||
return render(request, 'router_manager/sshkey_list.html', context=context)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_manage_sshkey(request):
|
||||
if request.GET.get('uuid'):
|
||||
sshkey = get_object_or_404(SSHKey, uuid=request.GET.get('uuid'))
|
||||
if request.GET.get('action') == 'delete':
|
||||
if request.GET.get('confirmation') == 'delete':
|
||||
sshkey.delete()
|
||||
messages.success(request, 'SSH Key deleted successfully')
|
||||
return redirect('ssh_keys_list')
|
||||
else:
|
||||
messages.warning(request, 'SSH Key not deleted|Invalid confirmation')
|
||||
return redirect('ssh_keys_list')
|
||||
else:
|
||||
sshkey = None
|
||||
|
||||
form = SSHKeyForm(request.POST or None, instance=sshkey)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, 'SSH Key saved successfully')
|
||||
return redirect('ssh_keys_list')
|
||||
|
||||
context = {
|
||||
'form': form,
|
||||
'page_title': 'Manage SSH Key',
|
||||
'instance': sshkey
|
||||
}
|
||||
return render(request, 'generic_form.html', context=context)
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.urls import path
|
|||
from dashboard.views import view_dashboard, view_status
|
||||
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_router_list, view_manage_router
|
||||
from router_manager.views import view_router_list, view_manage_router, view_router_group_list, view_ssh_key_list, view_manage_router_group, view_manage_sshkey
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
@ -16,4 +16,8 @@ urlpatterns = [
|
|||
path('accounts/logout/', view_logout, name='logout'),
|
||||
path('router/list/', view_router_list, name='router_list'),
|
||||
path('router/manage/', view_manage_router, name='manage_router'),
|
||||
path('router/group_list/', view_router_group_list, name='router_group_list'),
|
||||
path('router/ssh_keys/', view_ssh_key_list, name='ssh_keys_list'),
|
||||
path('router/manage_group/', view_manage_router_group, name='manage_router_group'),
|
||||
path('router/manage_sshkey/', view_manage_sshkey, name='manage_sshkey'),
|
||||
]
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
<link rel="stylesheet" href="/static/AdminLTE-3.2.0/plugins/overlayScrollbars/css/OverlayScrollbars.min.css">
|
||||
<!-- Daterange picker -->
|
||||
<link rel="stylesheet" href="/static/AdminLTE-3.2.0/plugins/daterangepicker/daterangepicker.css">
|
||||
<!-- summernote -->
|
||||
{% comment %}<!-- summernote -->
|
||||
<link rel="stylesheet" href="/static/AdminLTE-3.2.0/plugins/summernote/summernote-bs4.min.css">
|
||||
{% endcomment %}
|
||||
|
||||
<style>
|
||||
.min-width {
|
||||
|
@ -132,7 +133,7 @@
|
|||
<!-- Content Header (Page header) -->
|
||||
<div class="content-header">
|
||||
<div class="container-fluid">
|
||||
{% if page_title %}
|
||||
{% comment %}{% if page_title %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1 class="m-0">{{ page_title }}</h1>
|
||||
|
@ -155,7 +156,7 @@
|
|||
</ol>
|
||||
</div><!-- /.col -->
|
||||
</div><!-- /.row -->
|
||||
{% endif %}
|
||||
{% endif %}{% endcomment %}
|
||||
</div><!-- /.container-fluid -->
|
||||
</div>
|
||||
<!-- /.content-header -->
|
||||
|
@ -235,8 +236,9 @@
|
|||
<script src="/static/AdminLTE-3.2.0/plugins/daterangepicker/daterangepicker.js"></script>
|
||||
<!-- Tempusdominus Bootstrap 4 -->
|
||||
<script src="/static/AdminLTE-3.2.0/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
|
||||
<!-- Summernote -->
|
||||
{% comment %}<!-- Summernote -->
|
||||
<script src="/static/AdminLTE-3.2.0/plugins/summernote/summernote-bs4.min.js"></script>
|
||||
{% endcomment %}
|
||||
<!-- overlayScrollbars -->
|
||||
<script src="/static/AdminLTE-3.2.0/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
|
|
54
templates/router_manager/router_group_list.html
Normal file
54
templates/router_manager/router_group_list.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class='row'>
|
||||
<div class='col-lg-12'>
|
||||
<div class="card card-primary card-outline">
|
||||
{% if page_title %}
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{{ page_title }}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
{% include 'router_manager/router_nav_tabs.html' %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Default</th>
|
||||
<th>Internal Notes</th>
|
||||
<th>Routers</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for router_group in router_group_list %}
|
||||
<tr>
|
||||
<td>{{ router_group.name }}</td>
|
||||
<td>{% if router_group.default_group %}<i class="fas fa-check"></i>{% endif %}
|
||||
</td>
|
||||
<td>{{ router_group.internal_notes }}</td>
|
||||
<td>{{ router_group.routers.count }}</td>
|
||||
<td class="min-width">
|
||||
<a href="/router/manage_group/?uuid={{ router_group.uuid }}"><i
|
||||
class="fas fa-edit"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="/router/manage_group/" class="btn btn-primary">Add Router Group</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -11,6 +11,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
{% include 'router_manager/router_nav_tabs.html' %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-hover">
|
||||
|
@ -20,9 +21,9 @@
|
|||
<th>Address</th>
|
||||
<th>Enabled</th>
|
||||
<th>Status</th>
|
||||
<th>Groups</th>
|
||||
<th>Authentication</th>
|
||||
<th></th>
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for router in router_list %}
|
||||
|
@ -42,6 +43,9 @@
|
|||
---
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ router.routergroup_set.count }}
|
||||
</td>
|
||||
<td>
|
||||
{% if router.ssh_key %}
|
||||
{{ router.ssh_key }}
|
||||
|
@ -54,7 +58,6 @@
|
|||
<td class="min-width">
|
||||
<a href="/router/manage/?uuid={{ router.uuid }}"><i class="fas fa-edit"></i></a>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -65,8 +68,6 @@
|
|||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="/router/manage/" class="btn btn-primary">Add Router</a>
|
||||
<a href="#" class="btn btn-outline-primary">Router Groups</a>
|
||||
<a href="#" class="btn btn-outline-primary">SSH Keys</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
34
templates/router_manager/router_nav_tabs.html
Normal file
34
templates/router_manager/router_nav_tabs.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.path == '/router/list/' %}active{% endif %}" href="/router/list/" role="tab">
|
||||
Routers
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.path == '/router/group_list/' %}active{% endif %}" href="/router/group_list/"
|
||||
role="tab">
|
||||
Router Groups
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.path == '/router/ssh_keys/' %}active{% endif %}" href="/router/ssh_keys/"
|
||||
role="tab">
|
||||
SSH Keys
|
||||
</a>
|
||||
</li>
|
||||
{% if filter_group_list %}
|
||||
<!-- Dropdown aligned to the right -->
|
||||
<li class="nav-item dropdown ml-auto">
|
||||
<a class="nav-link dropdown-toggle " href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
{% if filter_group %}{{ filter_group }}{% else %}All Routers{% endif %}
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="?filter_group=all">All Routers</a>
|
||||
{% for group_temp in filter_group_list %}
|
||||
<a class="dropdown-item" href="?filter_group={{ group_temp.uuid }}">{{ group_temp.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
52
templates/router_manager/sshkey_list.html
Normal file
52
templates/router_manager/sshkey_list.html
Normal file
|
@ -0,0 +1,52 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class='row'>
|
||||
<div class='col-lg-12'>
|
||||
<div class="card card-primary card-outline">
|
||||
{% if page_title %}
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{{ page_title }}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
{% include 'router_manager/router_nav_tabs.html' %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Public Key</th>
|
||||
<th>Routers</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for sshkey in sshkey_list %}
|
||||
<tr>
|
||||
<td>{{ sshkey.name }}</td>
|
||||
<td>{{ sshkey.public_key }}</td>
|
||||
<td>{{ sshkey.router_set.count }}</td>
|
||||
<td class="min-width">
|
||||
<a href="/router/manage_sshkey/?uuid={{ sshkey.uuid }}"><i
|
||||
class="fas fa-edit"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="/router/manage_sshkey/" class="btn btn-primary">Add SSH Key</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue