Commit 98577a78 by Kálmán Viktor

dashboard: js part of mass vm ops

parent af03144a
...@@ -60,23 +60,6 @@ $(function() { ...@@ -60,23 +60,6 @@ $(function() {
return retval; return retval;
}); });
$('#vm-list-group-migrate').click(function() {
// pass?
});
$('.vm-list-details').popover({
'placement': 'auto',
'html': true,
'trigger': 'hover'
});
$('.vm-list-connect').popover({
'placement': 'left',
'html': true,
'trigger': 'click'
});
$('tbody a').mousedown(function(e) { $('tbody a').mousedown(function(e) {
// parent tr doesn't get selected when clicked // parent tr doesn't get selected when clicked
e.stopPropagation(); e.stopPropagation();
...@@ -89,42 +72,6 @@ $(function() { ...@@ -89,42 +72,6 @@ $(function() {
} }
}); });
/* rename */
$("#vm-list-rename-button, .vm-details-rename-button").click(function() {
$("#vm-list-column-name", $(this).closest("tr")).hide();
$("#vm-list-rename", $(this).closest("tr")).css('display', 'inline');
$("#vm-list-rename-name", $(this).closest("tr")).focus();
});
/* rename ajax */
$('.vm-list-rename-submit').click(function() {
var row = $(this).closest("tr")
var name = $('#vm-list-rename-name', row).val();
var url = '/dashboard/vm/' + row.children("td:first-child").text().replace(" ", "") + '/';
$.ajax({
method: 'POST',
url: url,
data: {'new_name': name},
headers: {"X-CSRFToken": getCookie('csrftoken')},
success: function(data, textStatus, xhr) {
$("#vm-list-column-name", row).html(
$("<a/>", {
'class': "real-link",
href: "/dashboard/vm/" + data['vm_pk'] + "/",
text: data['new_name']
})
).show();
$('#vm-list-rename', row).hide();
// addMessage(data['message'], "success");
},
error: function(xhr, textStatus, error) {
addMessage("Error during renaming!", "danger");
}
});
return false;
});
/* group actions */ /* group actions */
...@@ -143,17 +90,28 @@ $(function() { ...@@ -143,17 +90,28 @@ $(function() {
return false; return false;
}); });
/* mass vm delete */
$('#vm-list-group-delete').click(function() { /* mass operations */
addModalConfirmation(massDeleteVm, $("#vm-mass-ops").on('click', '.mass-operation', function(e) {
{ var icon = $(this).children("i").addClass('fa-spinner fa-spin');
'url': '/dashboard/vm/mass-delete/', params = "?a";
'data': { for(var i=0; i<selected.length; i++) {
'selected': selected, params += "&vm=" + selected[i].vm;
'v': collectIds(selected)
} }
$.ajax({
type: 'GET',
url: $(this).attr('href') + params,
success: function(data) {
icon.removeClass("fa-spinner fa-spin");
$('body').append(data);
$('#confirmation-modal').modal('show');
$('#confirmation-modal').on('hidden.bs.modal', function() {
$('#confirmation-modal').remove();
});
$("[title]").tooltip({'placement': "left"});
} }
); });
return false; return false;
}); });
...@@ -181,8 +139,52 @@ $(function() { ...@@ -181,8 +139,52 @@ $(function() {
$(".vm-list-table th a").on("click", function(event) { $(".vm-list-table th a").on("click", function(event) {
event.preventDefault(); event.preventDefault();
}); });
if(checkStatusUpdate()) {
updateStatuses(1);
}
}); });
function checkStatusUpdate() {
if($("#vm-list-table tbody td.state i").hasClass("fa-spin")) {
return true;
}
}
function updateStatuses(runs) {
$.get("/dashboard/vm/list/?compact", function(result) {
$("#vm-list-table tbody tr").each(function() {
vm = $(this).data("vm-pk");
status_td = $(this).find("td.state");
status_icon = status_td.find("i");
status_text = status_td.find("span");
if(vm in result) {
if(result[vm].in_status_change) {
if(!status_icon.hasClass("fa-spin")) {
status_icon.prop("class", "fa fa-spinner fa-spin");
}
} else {
status_icon.prop("class", "fa " + result[vm].icon);
}
status_text.text(result[vm].status);
} else {
$(this).remove();
}
});
if(checkStatusUpdate()) {
setTimeout(
function() {updateStatuses(runs + 1)},
1000 + Math.exp(runs * 0.05)
);
}
});
}
function isAlreadySelected(vm) { function isAlreadySelected(vm) {
for(var i=0; i<selected.length; i++) for(var i=0; i<selected.length; i++)
if(selected[i].vm == vm) if(selected[i].vm == vm)
......
...@@ -23,13 +23,14 @@ ...@@ -23,13 +23,14 @@
</div> </div>
</form> </form>
</div> </div>
<p> <div id="vm-mass-ops">
{% for o in ops %} {% for o in ops %}
<a href="{{ o.get_url }}" class="btn btn-xs btn-{{ o.effect }}" title="{{ o.name }}"> <a href="{{ o.get_url }}" class="btn btn-xs btn-{{ o.effect }} mass-operation"
title="{{ o.name }}">
<i class="fa fa-{{ o.icon }}"></i> <i class="fa fa-{{ o.icon }}"></i>
</a> </a>
{% endfor %} {% endfor %}
</p> </div>
<div class="panel-body vm-list-group-control"> <div class="panel-body vm-list-group-control">
<p> <p>
<strong>{% trans "Group actions" %}</strong> <strong>{% trans "Group actions" %}</strong>
...@@ -41,7 +42,8 @@ ...@@ -41,7 +42,8 @@
</p> </p>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<table class="table table-bordered table-striped table-hover vm-list-table"> <table class="table table-bordered table-striped table-hover vm-list-table"
id="vm-list-table">
<thead><tr> <thead><tr>
<th data-sort="int" class="orderable pk sortable vm-list-table-thin" style="min-width: 50px;"> <th data-sort="int" class="orderable pk sortable vm-list-table-thin" style="min-width: 50px;">
{% trans "ID" as t %} {% trans "ID" as t %}
...@@ -68,7 +70,14 @@ ...@@ -68,7 +70,14 @@
<tr class="{% cycle 'odd' 'even' %}" data-vm-pk="{{ i.pk }}"> <tr class="{% cycle 'odd' 'even' %}" data-vm-pk="{{ i.pk }}">
<td class="pk"><div id="vm-{{i.pk}}">{{i.pk}}</div> </td> <td class="pk"><div id="vm-{{i.pk}}">{{i.pk}}</div> </td>
<td class="name"><a class="real-link" href="{% url "dashboard.views.detail" i.pk %}">{{ i.name }}</a> </td> <td class="name"><a class="real-link" href="{% url "dashboard.views.detail" i.pk %}">{{ i.name }}</a> </td>
<td class="state">{{ i.get_status_display }}</td> <td class="state">
<i class="fa
{% if i.is_in_status_change %}
fa-spin fa-spinner
{% else %}
{{ i.get_status_icon }}{% endif %}"></i>
<span>{{ i.get_status_display }}</span>
</td>
<td> <td>
{% include "dashboard/_display-name.html" with user=i.owner show_org=True %} {% include "dashboard/_display-name.html" with user=i.owner show_org=True %}
</td> </td>
...@@ -104,6 +113,5 @@ ...@@ -104,6 +113,5 @@
{% block extra_js %} {% block extra_js %}
<script src="{{ STATIC_URL}}dashboard/vm-list.js"></script> <script src="{{ STATIC_URL}}dashboard/vm-list.js"></script>
<script src="{{ STATIC_URL}}dashboard/vm-common.js"></script>
<script src="{{ STATIC_URL}}dashboard/js/stupidtable.min.js"></script> <script src="{{ STATIC_URL}}dashboard/js/stupidtable.min.js"></script>
{% endblock %} {% endblock %}
...@@ -1648,6 +1648,24 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView): ...@@ -1648,6 +1648,24 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
if self.request.is_ajax(): if self.request.is_ajax():
return self._create_ajax_request()
else:
return super(VmList, self).get(*args, **kwargs)
def _create_ajax_request(self):
if self.request.GET.get("compact") is not None:
instances = Instance.get_objects_with_level(
"user", self.request.user).filter(destroyed_at=None)
statuses = {}
for i in instances:
statuses[i.pk] = {
'status': i.get_status_display(),
'icon': i.get_status_icon(),
'in_status_change': i.is_in_status_change(),
}
return HttpResponse(json.dumps(statuses),
content_type="application/json")
else:
favs = Instance.objects.filter( favs = Instance.objects.filter(
favourite__user=self.request.user).values_list('pk', flat=True) favourite__user=self.request.user).values_list('pk', flat=True)
instances = Instance.get_objects_with_level( instances = Instance.get_objects_with_level(
...@@ -1659,13 +1677,12 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView): ...@@ -1659,13 +1677,12 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
'icon': i.get_status_icon(), 'icon': i.get_status_icon(),
'host': "" if not i.primary_host else i.primary_host.hostname, 'host': "" if not i.primary_host else i.primary_host.hostname,
'status': i.get_status_display(), 'status': i.get_status_display(),
'fav': i.pk in favs} for i in instances] 'fav': i.pk in favs,
} for i in instances]
return HttpResponse( return HttpResponse(
json.dumps(list(instances)), # instances is ValuesQuerySet json.dumps(list(instances)), # instances is ValuesQuerySet
content_type="application/json", content_type="application/json",
) )
else:
return super(VmList, self).get(*args, **kwargs)
def get_queryset(self): def get_queryset(self):
logger.debug('VmList.get_queryset() called. User: %s', logger.debug('VmList.get_queryset() called. User: %s',
......
...@@ -988,3 +988,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, ...@@ -988,3 +988,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
instance=self, succeeded=None, parent=None).latest("started") instance=self, succeeded=None, parent=None).latest("started")
except InstanceActivity.DoesNotExist: except InstanceActivity.DoesNotExist:
return None return None
def is_in_status_change(self):
latest = self.get_latest_activity_in_progress()
return (latest and latest.resultant_state is not None
and self.status != latest.resultant_state)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment