Commit 32edaf0d by Kálmán Viktor

dashboard: spin the status icon if new resultant state

also fix add a hash function to check whether we should
update the activity feed

Closes #230
parent 9ea843e9
var show_all = false; var show_all = false;
var in_progress = false; var in_progress = false;
var activity_hash = 5;
$(function() { $(function() {
/* do we need to check for new activities */ /* do we need to check for new activities */
...@@ -359,17 +360,6 @@ function decideActivityRefresh() { ...@@ -359,17 +360,6 @@ function decideActivityRefresh() {
return check; return check;
} }
/* unescapes html got via the request, also removes whitespaces and replaces all ' with " */
function unescapeHTML(html) {
return html.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&').replace(/&ndash;/g, "–").replace(/\//g, "").replace(/'/g, '"').replace(/&#39;/g, "'").replace(/ /g, '');
}
/* the html page contains some tags that were modified via js (titles for example), we delete these
also some html tags are closed with / */
function changeHTML(html) {
return html.replace(/data-original-title/g, "title").replace(/title=""/g, "").replace(/\//g, '').replace(/ /g, '');
}
function checkNewActivity(runs) { function checkNewActivity(runs) {
var instance = location.href.split('/'); instance = instance[instance.length - 2]; var instance = location.href.split('/'); instance = instance[instance.length - 2];
...@@ -378,19 +368,24 @@ function checkNewActivity(runs) { ...@@ -378,19 +368,24 @@ function checkNewActivity(runs) {
url: '/dashboard/vm/' + instance + '/activity/', url: '/dashboard/vm/' + instance + '/activity/',
data: {'show_all': show_all}, data: {'show_all': show_all},
success: function(data) { success: function(data) {
if(show_all) { /* replace on longer string freezes the spinning stuff */ var new_activity_hash = (data['activities'] + "").hashCode();
if(new_activity_hash != activity_hash) {
$("#activity-refresh").html(data['activities']); $("#activity-refresh").html(data['activities']);
} else {
a = unescapeHTML(data['activities']);
b = changeHTML($("#activity-refresh").html());
if(a != b)
$("#activity-refresh").html(data['activities']);
} }
activity_hash = new_activity_hash;
$("#ops").html(data['ops']); $("#ops").html(data['ops']);
$("#disk-ops").html(data['disk_ops']); $("#disk-ops").html(data['disk_ops']);
$("[title]").tooltip(); $("[title]").tooltip();
$("#vm-details-state i").prop("class", "fa " + data['icon']); /* changing the status text */
var icon = $("#vm-details-state i");
if(data['is_new_state']) {
if(!icon.hasClass("fa-spin"))
icon.prop("class", "fa fa-spinner fa-spin");
} else {
icon.prop("class", "fa " + data['icon']);
}
$("#vm-details-state span").html(data['human_readable_status'].toUpperCase()); $("#vm-details-state span").html(data['human_readable_status'].toUpperCase());
if(data['status'] == "RUNNING") { if(data['status'] == "RUNNING") {
$("[data-target=#_console]").attr("data-toggle", "pill").attr("href", "#console").parent("li").removeClass("disabled"); $("[data-target=#_console]").attr("data-toggle", "pill").attr("href", "#console").parent("li").removeClass("disabled");
...@@ -421,3 +416,14 @@ function checkNewActivity(runs) { ...@@ -421,3 +416,14 @@ function checkNewActivity(runs) {
} }
}); });
} }
String.prototype.hashCode = function() {
var hash = 0, i, chr, len;
if (this.length == 0) return hash;
for (i = 0, len = this.length; i < len; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
...@@ -63,7 +63,11 @@ ...@@ -63,7 +63,11 @@
<div class="col-md-4" id="vm-info-pane"> <div class="col-md-4" id="vm-info-pane">
<div class="big"> <div class="big">
<span id="vm-details-state" class="label label-success"> <span id="vm-details-state" class="label label-success">
<i class="fa {{ instance.get_status_icon }}"></i> <i class="fa
{% if is_new_state %}
fa-spinner fa-spin
{% else %}
{{ instance.get_status_icon }}{% endif %}"></i>
<span>{{ instance.get_status_display|upper }}</span> <span>{{ instance.get_status_display|upper }}</span>
</span> </span>
</div> </div>
......
...@@ -310,6 +310,9 @@ class VmDetailView(CheckedDetailView): ...@@ -310,6 +310,9 @@ class VmDetailView(CheckedDetailView):
activities = activities[:10] activities = activities[:10]
context['activities'] = activities context['activities'] = activities
context['show_show_all'] = show_show_all context['show_show_all'] = show_show_all
latest = instance.get_latest_activity_in_progress()
context['is_new_state'] = (latest and
instance.status != latest.resultant_state)
Please register or sign in to reply
context['vlans'] = Vlan.get_objects_with_level( context['vlans'] = Vlan.get_objects_with_level(
'user', self.request.user 'user', self.request.user
...@@ -2456,6 +2459,9 @@ def vm_activity(request, pk): ...@@ -2456,6 +2459,9 @@ def vm_activity(request, pk):
response['human_readable_status'] = instance.get_status_display() response['human_readable_status'] = instance.get_status_display()
response['status'] = instance.status response['status'] = instance.status
response['icon'] = instance.get_status_icon() response['icon'] = instance.get_status_icon()
latest = instance.get_latest_activity_in_progress()
response['is_new_state'] = (latest and
instance.status != latest.resultant_state)
context = { context = {
'instance': instance, 'instance': instance,
......
...@@ -975,3 +975,10 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, ...@@ -975,3 +975,10 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
return vm_tasks.screenshot.apply_async(args=[self.vm_name], return vm_tasks.screenshot.apply_async(args=[self.vm_name],
queue=queue_name queue=queue_name
).get(timeout=timeout) ).get(timeout=timeout)
def get_latest_activity_in_progress(self):
try:
return InstanceActivity.objects.filter(
instance=self, succeeded=None).latest("started")
  • we could maybe filter to top-level activities (the ones with no parent)

    or also to those, which have any resultant_state (but that should be a parameter, or the function name is misleading)

    Edited
Please register or sign in to reply
except InstanceActivity.DoesNotExist:
return None
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