Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion openwisp_ipam/static/openwisp-ipam/css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
.subnet-visual{
margin: 10px 20px 0;
padding: 0;
}

section.subnet-visual{
overflow-anchor: none;
overflow-y: scroll;
height: 700px;
Expand All @@ -15,7 +18,7 @@
width: 120px;
text-align: center;
padding: 5px 0;
margin: 0 5px 10px 5px;
margin: 0 10px 10px 0px;
border-radius: 0;
color: #fff;
background: rgba(20, 102, 26, 0.9);
Expand Down Expand Up @@ -47,3 +50,6 @@
}

.subnet-visual .page{ display: inline }

#goto-input{ padding: 5px 10px }
#goto-button{ padding: 7px 10px }
68 changes: 58 additions & 10 deletions openwisp_ipam/static/openwisp-ipam/js/subnet.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ django.jQuery(function ($) {
// Open the specific subnet page that used clicked on.
document.location.href = data.node.a_attr.href;
});

// go to keyup
$('#goto-input').on('keyup', function (event) {
event.preventDefault();
if (event.key === 'Enter') {
django.jQuery('#goto-button').trigger('click');
}
});
});


Expand All @@ -35,6 +43,7 @@ function initHostsInfiniteScroll($, current_subnet, address_add_url, address_cha
fetchedPages = [],
busy = false,
nextPageUrl = '/api/v1/subnet/' + current_subnet + '/hosts/',
searchQuery = '',
lastRenderedPage = 0; //1 based indexing (0 -> no page rendered)
function addressListItem(addr) {
var id = normalizeIP(addr.address);
Expand All @@ -58,11 +67,47 @@ function initHostsInfiniteScroll($, current_subnet, address_add_url, address_cha
});
return div;
}
function validateIp(ip_address, callback) {
if (ip_address === '') {
callback(true);
return;
}
$.ajax({
type: 'GET',
url: '/api/v1/subnet/' + current_subnet + '/hosts/?start=' + ip_address,
success: function (res) {
callback(res.results[0].address === ip_address);
},
error: function (error) {
callback(false);
throw error;
},
});
}
function goTo() {
var input = $("#goto-input").val().toLowerCase().trim();
validateIp(input, function (isValid) {
if (isValid) {
$("#invalid-address").hide();
if (input !== searchQuery) {
searchQuery = input;
nextPageUrl = '/api/v1/subnet/' + current_subnet + '/hosts/?start=' + searchQuery;
$('#subnet-visual').empty();
fetchedPages = [];
lastRenderedPage = 0;
busy = false;
onUpdate();
}
} else {
$("#invalid-address").show();
}
});
}
function appendPage() {
$('.subnet-visual').append(pageContainer(fetchedPages[lastRenderedPage]));
$('#subnet-visual').append(pageContainer(fetchedPages[lastRenderedPage]));
if (lastRenderedPage >= renderedPages) {
var removedDiv = $('.subnet-visual div:first');
$('.subnet-visual').scrollTop($('.subnet-visual').scrollTop() - removedDiv.height());
var removedDiv = $('#subnet-visual div:first');
$('#subnet-visual').scrollTop($('#subnet-visual').scrollTop() - removedDiv.height());
removedDiv.remove();
}
lastRenderedPage += 1;
Expand Down Expand Up @@ -97,26 +142,29 @@ function initHostsInfiniteScroll($, current_subnet, address_add_url, address_cha
function pageUp() {
busy = true;
if (lastRenderedPage > renderedPages) {
$('.subnet-visual div:last').remove();
$('#subnet-visual div:last').remove();
var addedDiv = pageContainer(fetchedPages[lastRenderedPage - renderedPages - 1]);
$('.subnet-visual').prepend(addedDiv);
$('.subnet-visual').scrollTop($('.subnet-visual').scrollTop() + addedDiv.height());
$('#subnet-visual').prepend(addedDiv);
$('#subnet-visual').scrollTop($('#subnet-visual').scrollTop() + addedDiv.height());
lastRenderedPage -= 1;
}
busy = false;
}
function onUpdate() {
if (!busy) {
var scrollTop = $('.subnet-visual').scrollTop(),
scrollBottom = scrollTop + $('.subnet-visual').innerHeight(),
height = $('.subnet-visual')[0].scrollHeight;
var scrollTop = $('#subnet-visual').scrollTop(),
scrollBottom = scrollTop + $('#subnet-visual').innerHeight(),
height = $('#subnet-visual')[0].scrollHeight;
if (height * 0.75 <= scrollBottom) {
pageDown();
} else if (height * 0.25 >= scrollTop) {
pageUp();
}
}
}
$('.subnet-visual').scroll(onUpdate);
$("#goto-button").on("click", function () {
goTo();
});
$('#subnet-visual').scroll(onUpdate);
onUpdate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,17 @@ <h2>{% trans 'Network Hierarchical View' %}</h2>

<div id="graph"></div>

<h3>{% trans 'Subnet Visual Display' %}</h3>
<section class="subnet-visual{% if original.subnet.version == 6 %} ipv6{% endif %}">
<h3 class="subnet-visual">{% trans 'Subnet Visual Display' %}</h3>
<div class="subnet-visual">
<form onsubmit="return false">
<input id="goto-input" onkeypress="return event.keyCode != 13;" placeholder="Jump to" />
<input id="goto-button" type="button" value="Go" />
</form>
<ul id="invalid-address" class="errorlist" style="display:none;">
<li>{% trans 'Address not valid for subnet' %}</li>
</ul>
</div>
<section id="subnet-visual" class="subnet-visual{% if original.subnet.version == 6 %} ipv6{% endif %}">
</section>
{% endif %}
{% endblock %}
Expand All @@ -38,11 +47,11 @@ <h3>{% trans 'Subnet Visual Display' %}</h3>
{% if original and not is_popup %}
<script type="text/javascript">
var current_subnet = '{{ original.pk }}';
var IpAddUrl = '{% url ipaddress_add_url %}'
var IpChangeUrl = '{% url ipaddress_change_url "1234" %}'
var ipAddUrl = '{% url ipaddress_add_url %}'
var ipChangeUrl = '{% url ipaddress_change_url "1234" %}'
django.jQuery(document).ready(function () {
initHostsInfiniteScroll(django.jQuery, current_subnet, IpAddUrl, IpChangeUrl, {{ ip_uuid| safe}})
});
initHostsInfiniteScroll(django.jQuery, current_subnet, ipAddUrl, ipChangeUrl, {{ ip_uuid| safe}})
});
// Nested Subnet Tree
subnet_tree = [];
subnet_tree.push(
Expand Down
8 changes: 6 additions & 2 deletions openwisp_ipam/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ def test_ipv4_subnet_change(self):
)
response = self.client.get(url)
self.assertContains(response, 'ok')
self.assertContains(response, '<h3>Subnet Visual Display</h3>')
self.assertContains(
response, '<h3 class="subnet-visual">Subnet Visual Display</h3>'
)

def test_ipv6_subnet_change(self):
subnet = self._create_subnet(
Expand All @@ -72,7 +74,9 @@ def test_ipv6_subnet_change(self):
follow=True,
)
self.assertContains(response, 'ok')
self.assertContains(response, '<h3>Subnet Visual Display</h3>')
self.assertContains(
response, '<h3 class="subnet-visual">Subnet Visual Display</h3>'
)

def test_subnet_invalid_entry(self):
post_data = self._post_data(
Expand Down