Commit 695cd9bd by Kálmán Viktor

Merge branch 'issue-vm-ops' into 'master'

Issue Vm Ops

VM operations with form were kinda after an unsuccessful try. Without Javascript they still redirect to a page that seems to miss context data, but if javascript is enabled they work nice.
parents d48175e1 7916199f
...@@ -882,8 +882,6 @@ class VmDownloadDiskForm(forms.Form): ...@@ -882,8 +882,6 @@ class VmDownloadDiskForm(forms.Form):
@property @property
def helper(self): def helper(self):
helper = FormHelper(self) helper = FormHelper(self)
helper.add_input(Submit("submit", _("Create"),
css_class="btn btn-success"))
helper.form_tag = False helper.form_tag = False
return helper return helper
......
...@@ -511,7 +511,10 @@ function addMessage(text, type) { ...@@ -511,7 +511,10 @@ function addMessage(text, type) {
$('body').animate({scrollTop: 0}); $('body').animate({scrollTop: 0});
div = '<div style="display: none;" class="alert alert-' + type + '">' + text + '</div>'; div = '<div style="display: none;" class="alert alert-' + type + '">' + text + '</div>';
$('.messagelist').html('').append(div); $('.messagelist').html('').append(div);
$('.messagelist div').fadeIn(); var div = $('.messagelist div').fadeIn();
setTimeout(function() {
$(div).fadeOut();
}, 9000);
} }
......
...@@ -30,4 +30,56 @@ $(function() { ...@@ -30,4 +30,56 @@ $(function() {
}); });
return false; return false;
}); });
/* if the operation fails show the modal again */
$("body").on("click", "#op-form-send", function() {
var url = $(this).closest("form").prop("action");
$.ajax({
url: url,
headers: {"X-CSRFToken": getCookie('csrftoken')},
type: 'POST',
data: $(this).closest('form').serialize(),
success: function(data, textStatus, xhr) {
/* hide the modal we just submitted */
$('#confirmation-modal').modal("hide");
/* if it was successful trigger a click event on activity, this will
* - go to that tab
* - starts refreshing the activity
*/
if(data.success) {
$('a[href="#activity"]').trigger("click");
/* if there are messages display them */
if(data.messages && data.messages.length > 0) {
addMessage(data.messages.join("<br />"), "danger");
}
}
else {
/* if the post was not successful wait for the modal to disappear
* then append the new modal
*/
$('#confirmation-modal').on('hidden.bs.modal', function() {
$('body').append(data);
$('#confirmation-modal').modal('show');
$('#confirmation-modal').on('hidden.bs.modal', function() {
$('#confirmation-modal').remove();
});
});
}
},
error: function(xhr, textStatus, error) {
$('#confirmation-modal').modal("hide");
if (xhr.status == 500) {
addMessage("500 Internal Server Error", "danger");
} else {
addMessage(xhr.status + " Unknown Error", "danger");
}
}
});
return false;
});
}); });
...@@ -5,7 +5,7 @@ $(function() { ...@@ -5,7 +5,7 @@ $(function() {
} }
$('a[href="#activity"]').click(function(){ $('a[href="#activity"]').click(function(){
$('a[href="#activity"] i').addClass('icon-spin'); $('a[href="#activity"] i').addClass('icon-spin');
checkNewActivity(false,0); checkNewActivity(false, 1);
}); });
/* save resources */ /* save resources */
...@@ -341,6 +341,7 @@ function checkNewActivity(only_status, runs) { ...@@ -341,6 +341,7 @@ function checkNewActivity(only_status, runs) {
if(!only_status) { if(!only_status) {
$("#activity-timeline").html(data['activities']); $("#activity-timeline").html(data['activities']);
$("#ops").html(data['ops']); $("#ops").html(data['ops']);
$("#disk-ops").html(data['disk_ops']);
$("[title]").tooltip(); $("[title]").tooltip();
} }
......
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
<title>{% block title %}{% block title-page %}{% endblock %} | {% block title-site %}CIRCLE{% endblock %}{% endblock %}</title> <title>{% block title %}{% block title-page %}{% endblock %} | {% block title-site %}CIRCLE{% endblock %}{% endblock %}</title>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
......
...@@ -19,6 +19,8 @@ Do you want to do the following operation on {{obj}}: ...@@ -19,6 +19,8 @@ Do you want to do the following operation on {{obj}}:
<div class="pull-right"> <div class="pull-right">
<a class="btn btn-default" href="{{object.get_absolute_url}}" <a class="btn btn-default" href="{{object.get_absolute_url}}"
data-dismiss="modal">{% trans "Cancel" %}</a> data-dismiss="modal">{% trans "Cancel" %}</a>
<button class="btn btn-danger" type="submit">{% if op.icon %}<i class="icon-{{op.icon}}"></i> {% endif %}{{ op|capfirst }}</button> <button class="btn btn-danger" type="submit" id="op-form-send">
{% if op.icon %}<i class="icon-{{op.icon}}"></i> {% endif %}{{ op|capfirst }}
</button>
</div> </div>
</form> </form>
{% load i18n %}
{% for op in ops %}
{% if op.is_disk_operation %}
<a href="{{op.get_url}}" class="btn btn-success btn-xs
operation operation-{{op.op}} btn btn-default">
<i class="icon-{{op.icon}}"></i>
{{op.name}} </a>
{% endif %}
{% endfor %}
...@@ -47,18 +47,9 @@ ...@@ -47,18 +47,9 @@
<h3> <h3>
{% trans "Disks" %} {% trans "Disks" %}
<div class="pull-right"> <div class="pull-right">
{% if op.download_disk %} <div id="disk-ops">
<a href="{{op.download_disk.get_url}}" class="btn btn-success btn-xs {% include "dashboard/vm-detail/_disk-operations.html" %}
operation operation-{{op.download_disk.op}} btn btn-default"> </div>
<i class="icon-{{op.download_disk.icon}}"></i>
{{op.download_disk.name}} </a>
{% endif %}
{% if op.create_disk %}
<a href="{{op.create_disk.get_url}}" class="btn btn-success btn-xs
operation operation-{{op.create_disk.op}} btn btn-default">
<i class="icon-{{op.create_disk.icon}}"></i>
{{op.create_disk.name}} </a>
{% endif %}
</div> </div>
</h3> </h3>
......
...@@ -575,6 +575,19 @@ class VmOperationView(OperationView): ...@@ -575,6 +575,19 @@ class VmOperationView(OperationView):
model = Instance model = Instance
context_object_name = 'instance' # much simpler to mock object context_object_name = 'instance' # much simpler to mock object
def post(self, request, *args, **kwargs):
resp = super(VmOperationView, self).post(request, *args, **kwargs)
if request.is_ajax():
store = messages.get_messages(request)
store.used = True
return HttpResponse(
json.dumps({'success': True,
'messages': [unicode(m) for m in store]}),
content_type="application=json"
)
else:
return resp
class FormOperationMixin(object): class FormOperationMixin(object):
...@@ -594,8 +607,15 @@ class FormOperationMixin(object): ...@@ -594,8 +607,15 @@ class FormOperationMixin(object):
form = self.form_class(self.request.POST) form = self.form_class(self.request.POST)
if form.is_valid(): if form.is_valid():
extra.update(form.cleaned_data) extra.update(form.cleaned_data)
return super(FormOperationMixin, self).post( resp = super(FormOperationMixin, self).post(
request, extra, *args, **kwargs) request, extra, *args, **kwargs)
if request.is_ajax():
return HttpResponse(
json.dumps({'success': True}),
content_type="application=json"
)
else:
return resp
else: else:
return self.get(request) return self.get(request)
...@@ -606,6 +626,7 @@ class VmCreateDiskView(FormOperationMixin, VmOperationView): ...@@ -606,6 +626,7 @@ class VmCreateDiskView(FormOperationMixin, VmOperationView):
form_class = VmCreateDiskForm form_class = VmCreateDiskForm
show_in_toolbar = False show_in_toolbar = False
icon = 'hdd' icon = 'hdd'
is_disk_operation = True
class VmDownloadDiskView(FormOperationMixin, VmOperationView): class VmDownloadDiskView(FormOperationMixin, VmOperationView):
...@@ -614,6 +635,7 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView): ...@@ -614,6 +635,7 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView):
form_class = VmDownloadDiskForm form_class = VmDownloadDiskForm
show_in_toolbar = False show_in_toolbar = False
icon = 'download' icon = 'download'
is_disk_operation = True
class VmMigrateView(VmOperationView): class VmMigrateView(VmOperationView):
...@@ -2117,6 +2139,10 @@ def vm_activity(request, pk): ...@@ -2117,6 +2139,10 @@ def vm_activity(request, pk):
"dashboard/vm-detail/_operations.html", "dashboard/vm-detail/_operations.html",
RequestContext(request, context), RequestContext(request, context),
) )
response['disk_ops'] = render_to_string(
"dashboard/vm-detail/_disk-operations.html",
RequestContext(request, context),
)
return HttpResponse( return HttpResponse(
json.dumps(response), json.dumps(response),
......
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