Skip to content

Commit

Permalink
Merge pull request #205 from innogames/servershell_diff_objects
Browse files Browse the repository at this point in the history
Add diff command to servershell
  • Loading branch information
kofrezo committed Jan 20, 2022
2 parents 43403a5 + a9e8d1e commit db6f0d2
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 7 deletions.
10 changes: 9 additions & 1 deletion serveradmin/servershell/static/css/servershell.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,12 @@
width: 25%;
right: 0;
top: 1%;
}
}

.diff {
background-color: #f8d7da;
}

.equal {
background-color: #d1e7dd;
}
11 changes: 11 additions & 0 deletions serveradmin/servershell/static/js/diff.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let toggle_diff = function(element) {
let button = $(element);

if (button.attr('aria-pressed') === 'true') {
$('tbody tr').show();
}
else {
$('tbody tr').hide();
$('tbody td.diff').parent('tr').show();
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ $(document).ready(function() {
}
});
}
if (command === 'attr' || command === 'export') {
if (command === 'attr' || command === 'export' || command === 'diff') {
values = values.split(',').map(v => v.trim());
let search_string = values.pop();
let attribute_ids = get_attribute_ids(search_string, values);
Expand Down
21 changes: 20 additions & 1 deletion serveradmin/servershell/static/js/servershell/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ servershell.delete_attribute = function(object_id, attribute_id) {
*/
function validate_selected(min=1, max=-1) {
let selected = servershell.get_selected().length;
if ((min !== -1 && selected < min) || (max !== -1 && selected.length > max)) {
if ((min !== -1 && selected < min) || (max !== -1 && selected > max)) {
if (max === -1) {
servershell.alert(`You must select at least ${min} object(s)`, 'warning');
}
Expand Down Expand Up @@ -634,6 +634,25 @@ servershell.commands = {
servershell._ajax.abort();
servershell.alert('Pending request cancelled', 'success');
},
diff: function(attribute_ids) {
if (!validate_selected(2)) {
return;
}

attribute_ids = attribute_ids.split(',').map(a => a.trim()).filter(a => a !== '');
let unknown = attribute_ids.filter(a => servershell.attributes.find(b => b.attribute_id === a) === undefined);

if (unknown.length > 0) {
servershell.alert(`The attribute(s) ${unknown.join(', ')} doe not exist!`, 'warning');
return;
}

let objects = servershell.get_selected().map(o => `object=${o}`).join('&');
let attrs = attribute_ids.map(a => `attr=${a}`).join('&');
let url = servershell.urls.diff + '?' + objects + '&' + attrs;

window.open(url, '_blank');
},
};

$(document).ready(function() {
Expand Down
47 changes: 47 additions & 0 deletions serveradmin/servershell/templates/servershell/diff.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{% extends "base.html" %}

{% block title %}Diff{% endblock %}

{% block additional_styles %}
<link rel="stylesheet" href="{{ STATIC_URL }}css/servershell.css">
{% endblock %}

{% block content %}
<div class="row">
<div class="col-md-12">
<button class="btn btn-primary" data-toggle="button" aria-pressed="false" onclick="toggle_diff(this);">
Differences only
</button>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-sm table-borderless table-striped table-responsive">
<thead>
<tr>
<th scope="col">Attribute</th>
{% for host in hosts %}
<th scope="col">{{ host.hostname }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in diff_data %}
<tr>
<td>{{ row.0 }}</td>
{% with compare_to=row.1.0 %}
{% for value in row.1 %}
<td class="{% if value != compare_to %}diff{% else %}equal{% endif %}">{{ value }}</td>
{% endfor %}
{% endwith %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

{% block additional_scripts %}
<script src="{{ STATIC_URL }}js/diff.js"></script>
{% endblock %}
1 change: 1 addition & 0 deletions serveradmin/servershell/templates/servershell/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
commit: "{% url 'servershell_commit' %}",
history: "{% url 'serverdb_history' %}",
settings: "{% url 'servershell_save_settings' %}",
diff: "{% url 'servershell_diff' %}",
};

servershell.search_settings = {% autoescape off %}{{ search_settings|json }}{% endautoescape %};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ <h3>Available commands</h3>
Cancel running requests such as search.
</td>
</tr>
<tr id="cmd-diff">
<td>diff</td>
<td>[attribute]</td>
<td>
Show differences of attributes for selected objects.
</td>
</tr>
</tbody>
</table>
</div>
Expand Down
3 changes: 2 additions & 1 deletion serveradmin/servershell/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
new_object,
clone_object,
choose_ip_addr,
settings,
settings, diff,
)


Expand All @@ -30,4 +30,5 @@
path('clone', clone_object, name='servershell_clone'),
path('choose_ip_addr', choose_ip_addr, name='servershell_choose_ip_addr'),
path('settings', settings, name='servershell_save_settings'),
path('diff', diff, name='servershell_diff'),
]
47 changes: 44 additions & 3 deletions serveradmin/servershell/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import json
from distutils.util import strtobool
from ipaddress import IPv6Address, IPv4Address, ip_interface
from itertools import islice
from itertools import islice, chain

from django.contrib import messages
from django.contrib.auth.decorators import login_required
Expand All @@ -21,13 +21,14 @@
Http404,
JsonResponse,
HttpResponseBadRequest,
HttpResponseNotFound
HttpResponseNotFound, HttpRequest
)
from django.shortcuts import redirect
from django.shortcuts import redirect, render, get_object_or_404
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.html import mark_safe, escape as escape_html
from django.views.decorators.http import require_http_methods
from django.views.defaults import bad_request

from adminapi.datatype import DatatypeError
from adminapi.filters import Any, ContainedOnlyBy, filter_classes
Expand Down Expand Up @@ -511,3 +512,43 @@ def _prepare_regexp_html(regexp):
regexp_html = (escape_html(regexp).replace('|', '|&#8203;')
.replace(']', ']&#8203;').replace(')', ')&#8203;'))
return mark_safe(regexp_html)


@login_required
def diff(request: HttpRequest) -> HttpResponse:
attrs = request.GET.getlist('attr')
objects = request.GET.getlist('object')

if not objects or not all([o.isnumeric() for o in objects]):
return bad_request(request, HttpResponseBadRequest)

# Can raise ApiError for unknown attributes - let it flow ...
qs = Query({'object_id': Any(*objects)}, attrs if attrs else None)

diff_data = []
for attribute in sorted(set(chain(*[o.keys() for o in qs]))):
# object_id is always different and special
if attribute == 'object_id':
continue

# Show hostname only if request by user
if attribute == 'hostname' and attrs != [] and attribute not in attrs:
continue

values = []
for obj in qs:
values.append(obj[attribute])

diff_data.append([attribute, values])

# Fetch hostnames if not requested by user to display as header in result.
if 'hostname' in attrs:
hosts = qs
else:
hosts = Query({'object_id': Any(*objects)}, ['hostname'])

context = {
'hosts': hosts,
'diff_data': diff_data,
}
return render(request, 'servershell/diff.html', context)

0 comments on commit db6f0d2

Please sign in to comment.