Merge pull request #486 from tiwariav/task/3728/vm_teminate_animation
task/3728 vm termination animation
This commit is contained in:
		
				commit
				
					
						ae1a317bf9
					
				
			
		
					 8 changed files with 263 additions and 89 deletions
				
			
		|  | @ -561,6 +561,9 @@ msgstr "Aktueller Preis" | |||
| msgid "Your VM is" | ||||
| msgstr "Deine VM ist" | ||||
| 
 | ||||
| msgid "Terminating" | ||||
| msgstr "Beenden" | ||||
| 
 | ||||
| msgid "Pending" | ||||
| msgstr "In Vorbereitung" | ||||
| 
 | ||||
|  | @ -573,6 +576,11 @@ msgstr "Fehlgeschlagen" | |||
| msgid "Terminate VM" | ||||
| msgstr "VM Beenden" | ||||
| 
 | ||||
| msgid "Sorry, there was an unexpected error. Kindly retry." | ||||
| msgstr "" | ||||
| "Bitte entschuldige, es scheint ein unerwarteter Fehler aufgetreten zu sein. " | ||||
| "Versuche es doch bitte noch einmal." | ||||
| 
 | ||||
| msgid "Something doesn't work?" | ||||
| msgstr "Etwas funktioniert nicht?" | ||||
| 
 | ||||
|  | @ -591,6 +599,11 @@ msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst" | |||
| msgid "OK" | ||||
| msgstr "" | ||||
| 
 | ||||
| #, python-format | ||||
| msgid "" | ||||
| "Your Virtual Machine %(virtual_machine.name)s is successfully terminated!" | ||||
| msgstr "Deine Virtuelle Machine (VM) %(virtual_machine.name)s wurde erfolgreich beendet!" | ||||
| 
 | ||||
| msgid "Virtual Machines" | ||||
| msgstr "Virtuelle Maschinen" | ||||
| 
 | ||||
|  | @ -678,12 +691,20 @@ msgid "" | |||
| "contact Data Center Light Support." | ||||
| msgstr "Kontaktiere den Data Center Light Support." | ||||
| 
 | ||||
| msgid "Terminated" | ||||
| msgstr "Beendet" | ||||
| 
 | ||||
| msgid "Error terminating VM" | ||||
| msgstr "Fehler beenden VM" | ||||
| 
 | ||||
| msgid "Virtual Machine Cancellation" | ||||
| msgstr "VM Kündigung" | ||||
| 
 | ||||
| #, python-format | ||||
| msgid "VM %(VM_ID)s terminated successfully" | ||||
| msgstr "VM %(VM_ID)s erfolgreich beendet" | ||||
| #~ msgid "Close" | ||||
| #~ msgstr "Schliessen" | ||||
| 
 | ||||
| #~ msgid "VM %(VM_ID)s terminated successfully" | ||||
| #~ msgstr "VM %(VM_ID)s erfolgreich beendet" | ||||
| 
 | ||||
| #~ msgid "days" | ||||
| #~ msgstr "tage" | ||||
|  | @ -760,9 +781,6 @@ msgstr "VM %(VM_ID)s erfolgreich beendet" | |||
| #~ msgid "Ipv6" | ||||
| #~ msgstr "IPv6" | ||||
| 
 | ||||
| #~ msgid "Close" | ||||
| #~ msgstr "Schliessen" | ||||
| 
 | ||||
| #~ msgid "Cancel" | ||||
| #~ msgstr "Beenden" | ||||
| 
 | ||||
|  |  | |||
|  | @ -139,6 +139,10 @@ | |||
| .modal-text p:not(:last-of-type){ | ||||
| 	margin-bottom: 5px; | ||||
| } | ||||
| 
 | ||||
| .modal-title + .modal-footer { | ||||
|     margin-top: 5px; | ||||
| } | ||||
| .modal-footer { | ||||
|     border-top: 0px solid #e5e5e5; | ||||
|     width: 100%; | ||||
|  |  | |||
|  | @ -853,6 +853,9 @@ a.list-group-item-danger:focus, | |||
| .panel-danger > .panel-heading { | ||||
|     color: #eb4d5c; | ||||
| } | ||||
| .alert-danger{ | ||||
|     background: rgba(235, 204, 209, 0.2); | ||||
| } | ||||
| .has-error .form-control, | ||||
| .has-error .input-group-addon { | ||||
|     color: #eb4d5c; | ||||
|  |  | |||
|  | @ -290,6 +290,11 @@ | |||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .vm-vmid .alert { | ||||
|   margin-top: 15px; | ||||
|   margin-bottom: -60px; | ||||
| } | ||||
| 
 | ||||
| .vm-item-lg { | ||||
|   font-size: 22px; | ||||
|   margin-top: 5px; | ||||
|  | @ -305,6 +310,10 @@ | |||
|   color: #e47f2f; | ||||
| } | ||||
| 
 | ||||
| .vm-color-failed { | ||||
|   color: #eb4d5c; | ||||
| } | ||||
| 
 | ||||
| .vm-detail-item .value{ | ||||
|   font-weight: 400; | ||||
| } | ||||
|  | @ -512,7 +521,7 @@ | |||
|   color: #87B6EA; | ||||
| } | ||||
| 
 | ||||
| .vm-status, .vm-status-active, .vm-status-failed { | ||||
| .vm-status, .vm-status-active, .vm-status-failed, .vm-status-pending { | ||||
|   font-weight: 600; | ||||
| } | ||||
| .vm-status-active { | ||||
|  | @ -521,6 +530,9 @@ | |||
| .vm-status-failed { | ||||
|   color: #eb4d5c; | ||||
| } | ||||
| .vm-status-pending { | ||||
|   color: #e47f2f; | ||||
| } | ||||
| 
 | ||||
| @media (min-width:768px) { | ||||
|   .dashboard-subtitle { | ||||
|  | @ -628,3 +640,27 @@ | |||
|     right: 8px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .processing > .btn { | ||||
|   position: relative; | ||||
|   border-color: #eee; | ||||
| } | ||||
| .processing > .btn:hover, | ||||
| .processing > .btn:focus, | ||||
| .processing > .btn:active { | ||||
|   border-color: #eee; | ||||
| } | ||||
| 
 | ||||
| .processing > .btn:after { | ||||
|   content: ' '; | ||||
|   display: block; | ||||
|   position: absolute; | ||||
|   background-image: url('/static/hosting/img/ajax-loader.gif'); | ||||
|   background-repeat: no-repeat; | ||||
|   background-position: center; | ||||
|   background-color: #eee; | ||||
|   width: 100%; | ||||
|   top: 0; | ||||
|   height: 100%; | ||||
|   left: 0; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								hosting/static/hosting/img/ajax-loader.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								hosting/static/hosting/img/ajax-loader.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 404 B | 
|  | @ -1,4 +1,84 @@ | |||
| $(document).ready(function () { | ||||
| function VMTerminateStatus($container, url) { | ||||
|     $.ajax({ | ||||
|         url: url, | ||||
|         type: 'GET', | ||||
|         dataType: 'json', | ||||
|         success: function(data) { | ||||
|             VMTerminateSuccess($container, data); | ||||
|         }, | ||||
|         error: function() { | ||||
|             setTimeout(function(){ | ||||
|                 VMTerminateStatus($container, url); | ||||
|             }, 5000); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function VMTerminateActive($container, altText) { | ||||
|     $container.find('.alert-danger').addClass('hide'); | ||||
|     $container.addClass('processing') | ||||
|         .find('.vm-item-lg').attr('class', '') | ||||
|         .addClass('vm-item-lg vm-color-failed') | ||||
|         .text(altText); | ||||
|     $container.find('.btn').prop('disabled', true); | ||||
|     $('#confirm-cancel').modal('hide'); | ||||
| } | ||||
| 
 | ||||
| function VMTerminateSuccess($container, data) { | ||||
|     $container.addClass('terminate-success') | ||||
|         .find('.vm-item-lg').text(data.text); | ||||
|     $container.find('.btn').remove(); | ||||
|     $('#terminate-success').modal('show'); | ||||
| } | ||||
| 
 | ||||
| function VMTerminateFail($container, data, text) { | ||||
|     $container.addClass('terminate-fail') | ||||
|         .find('.vm-item-lg').text(text); | ||||
|     $container.find('.btn').prop('disabled', false); | ||||
|     $container.find('.alert-danger').text(data.text).removeClass('hide'); | ||||
|     $container.removeClass('processing'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| $(document).ready(function() { | ||||
|     $('#confirm-cancel').on('click', '.btn-ok', function(e) { | ||||
|         var url = $('#virtual_machine_cancel_form').attr('action'); | ||||
|         var $container = $('#terminate-VM'); | ||||
|         var text = $container.find('.vm-item-lg').text(); | ||||
|         var altText = $container.attr('data-alt'); | ||||
|         VMTerminateActive($container, altText); | ||||
| 
 | ||||
|         $.post(url) | ||||
|             .done(function(data) { | ||||
|                 if (data.status == true) { | ||||
|                     VMTerminateSuccess($container, data); | ||||
|                 } else { | ||||
|                     if ('text' in data) { | ||||
|                         VMTerminateFail($container, data, text); | ||||
|                     } else { | ||||
|                         VMTerminateStatus($container, url); | ||||
|                     } | ||||
|                 } | ||||
|             }) | ||||
|             .fail(function(data) { | ||||
|                 if (data.status==504) { | ||||
|                     VMTerminateStatus($container, url); | ||||
|                 } else { | ||||
|                     VMTerminateFail($container, data, text); | ||||
|                 } | ||||
|             }) | ||||
|     }); | ||||
| 
 | ||||
|     var hash = window.location.hash; | ||||
|     hash && $('ul.nav a[href="' + hash + '"]').tab('show'); | ||||
| 
 | ||||
|     $('.nav-tabs a').click(function(e) { | ||||
|         $(this).tab('show'); | ||||
|         var scrollmem = $('body').scrollTop() || $('html').scrollTop(); | ||||
|         window.location.hash = this.hash; | ||||
|         $('html,body').scrollTop(scrollmem); | ||||
|     }); | ||||
| 
 | ||||
|     $('.modal-text').removeClass('hide'); | ||||
|     var create_vm_form = $('#virtual_machine_create_form'); | ||||
|     create_vm_form.submit(function () { | ||||
|  | @ -32,19 +112,4 @@ $(document).ready(function () { | |||
|         }); | ||||
|         return false; | ||||
|     }); | ||||
| 
 | ||||
|     $('#confirm-cancel').on('click', '.btn-ok', function (e) { | ||||
|         $('#virtual_machine_cancel_form').trigger('submit'); | ||||
|     }); | ||||
| 
 | ||||
|     var hash = window.location.hash; | ||||
|     hash && $('ul.nav a[href="' + hash + '"]').tab('show'); | ||||
| 
 | ||||
|     $('.nav-tabs a').click(function (e) { | ||||
|         $(this).tab('show'); | ||||
|         var scrollmem = $('body').scrollTop() || $('html').scrollTop(); | ||||
|         window.location.hash = this.hash; | ||||
|         $('html,body').scrollTop(scrollmem); | ||||
|     }); | ||||
| 
 | ||||
| }); | ||||
|  |  | |||
|  | @ -53,22 +53,29 @@ | |||
| 				<h2 class="vm-detail-title">{% trans "Status" %} <img src="{% static 'hosting/img/connected.svg' %}" class="un-icon"></h2> | ||||
| 				<div class="vm-vmid"> | ||||
| 					<div class="vm-item-subtitle">{% trans "Your VM is" %}</div> | ||||
| 						<div id="terminate-VM" data-alt="{% trans 'Terminating' %}"> | ||||
| 							{% if virtual_machine.state == 'PENDING' %} | ||||
| 								<div class="vm-item-lg vm-color-pending">{% trans "Pending" %}</div> | ||||
| 							{% elif  virtual_machine.state == 'ACTIVE' %} | ||||
| 								<div class="vm-item-lg vm-color-online">{% trans "Online" %}</div> | ||||
| 							{% elif  virtual_machine.state == 'FAILED'%} | ||||
| 								<div class="vm-item-lg vm-color-failed">{% trans "Failed" %}</div> | ||||
| 							{% else %} | ||||
| 								<div class="vm-item-lg"></div> | ||||
| 							{% endif %} | ||||
| 							{% if not virtual_machine.status == 'canceled' %} | ||||
| 								<form method="POST" id="virtual_machine_cancel_form" class="cancel-form" action="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}"> | ||||
| 									{% csrf_token %} | ||||
| 								</form> | ||||
| 						<button data-href="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-vm-term">{% trans "Terminate VM" %}</button> | ||||
| 								<button data-toggle="modal" data-target="#confirm-cancel" class="btn btn-vm-term">{% trans "Terminate VM" %}</button> | ||||
| 								<div class="alert alert-danger hide"> | ||||
| 									{% trans "Sorry, there was an unexpected error. Kindly retry." %} | ||||
| 								</div> | ||||
| 							{% endif %} | ||||
| 						</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="vm-contact-us"> | ||||
| 			<div> | ||||
| 				<h2 class="vm-detail-title">{% trans "Support / Contact" %} <img class="un-icon visible-xs" src="{% static 'hosting/img/24-hours-support.svg' %}"></h2> | ||||
|  | @ -96,7 +103,7 @@ | |||
| 				</div> | ||||
|       	<div class="modal-body"> | ||||
| 					<div class="modal-icon"><i class="fa fa-ban" aria-hidden="true"></i></div> | ||||
| 					<h4 class="modal-title" id="ModalLabel">{% trans "Terminate your Virtual Machine"%}</h4> | ||||
| 					<h4 class="modal-title" id="ModalLabel">{% trans "Terminate your Virtual Machine" %}</h4> | ||||
| 					<div class="modal-text"> | ||||
| 						<p>{% trans "Do you want to cancel your Virtual Machine" %} ?</p> | ||||
| 						<p><strong>{{virtual_machine.name}}</strong></p> | ||||
|  | @ -109,4 +116,21 @@ | |||
|     </div> | ||||
| 	</div> | ||||
| 	<!-- / Cancel Modal --> | ||||
| 	<!-- Success Modal --> | ||||
| 	<div class="modal fade" id="terminate-success" tabindex="-1" role="dialog" aria-hidden="true"> | ||||
|     <div class="modal-dialog"> | ||||
|       <div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 				</div> | ||||
|         <div class="modal-body"> | ||||
| 					<div class="modal-icon"><i class="fa fa-check" aria-hidden="true"></i></div> | ||||
| 					<h4 class="modal-title" id="ModalLabel">{% blocktrans with machine_name=virtual_machine.name %}Your Virtual Machine <strong>{{machine_name}}</strong> is successfully terminated!{% endblocktrans %}</h4> | ||||
|           <div class="modal-footer"> | ||||
|             <a href="{% url 'hosting:virtual_machines' %}"	class="btn btn-success btn-wide">{% trans "OK" %}</a> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| 	</div> | ||||
| 	<!-- / Cancel Modal --> | ||||
| {%endblock%} | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import json | ||||
| import logging | ||||
| import uuid | ||||
| from time import sleep | ||||
| 
 | ||||
| from django import forms | ||||
| from django.conf import settings | ||||
|  | @ -10,16 +11,17 @@ from django.contrib.auth.tokens import default_token_generator | |||
| from django.core.exceptions import ValidationError | ||||
| from django.core.files.base import ContentFile | ||||
| from django.core.urlresolvers import reverse_lazy, reverse | ||||
| from django.http import Http404 | ||||
| from django.http import HttpResponseRedirect, HttpResponse | ||||
| from django.shortcuts import redirect | ||||
| from django.shortcuts import render | ||||
| 
 | ||||
| from django.http import Http404, HttpResponseRedirect, HttpResponse | ||||
| from django.shortcuts import redirect, render | ||||
| from django.utils.http import urlsafe_base64_decode | ||||
| from django.utils.safestring import mark_safe | ||||
| from django.utils.translation import get_language, ugettext_lazy as _ | ||||
| from django.views.generic import View, CreateView, FormView, ListView, \ | ||||
|     DetailView, \ | ||||
|     DeleteView, TemplateView, UpdateView | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.utils.translation import ugettext | ||||
| from django.views.generic import ( | ||||
|     View, CreateView, FormView, ListView, DetailView, DeleteView, | ||||
|     TemplateView, UpdateView | ||||
| ) | ||||
| from guardian.mixins import PermissionRequiredMixin | ||||
| from oca.pool import WrongIdError | ||||
| from stored_messages.api import mark_read | ||||
|  | @ -35,8 +37,9 @@ from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | |||
|     UserBillingAddressForm | ||||
| from utils.mailer import BaseEmail | ||||
| from utils.stripe_utils import StripeUtils | ||||
| from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, \ | ||||
|     LoginViewMixin | ||||
| from utils.views import ( | ||||
|     PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin | ||||
| ) | ||||
| from .forms import HostingUserSignupForm, HostingUserLoginForm, \ | ||||
|     UserHostingKeyForm, generate_ssh_key_name | ||||
| from .mixins import ProcessVMSelectionMixin | ||||
|  | @ -985,7 +988,19 @@ class VirtualMachineView(LoginRequiredMixin, View): | |||
|     def get(self, request, *args, **kwargs): | ||||
|         vm = self.get_object() | ||||
|         if vm is None: | ||||
|             if self.request.is_ajax(): | ||||
|                 storage = messages.get_messages(request) | ||||
|                 for m in storage: | ||||
|                     pass | ||||
|                 storage.used = True | ||||
|                 return HttpResponse( | ||||
|                     json.dumps({'text': ugettext('Terminated')}), | ||||
|                     content_type="application/json" | ||||
|                 ) | ||||
|             else: | ||||
|                 return redirect(reverse('hosting:virtual_machines')) | ||||
|         elif self.request.is_ajax(): | ||||
|             return HttpResponse() | ||||
|         try: | ||||
|             serializer = VirtualMachineSerializer(vm) | ||||
|             context = { | ||||
|  | @ -1000,6 +1015,7 @@ class VirtualMachineView(LoginRequiredMixin, View): | |||
|         return render(request, self.template_name, context) | ||||
| 
 | ||||
|     def post(self, request, *args, **kwargs): | ||||
|         response = {'status': False} | ||||
|         owner = self.request.user | ||||
|         vm = self.get_object() | ||||
| 
 | ||||
|  | @ -1009,17 +1025,29 @@ class VirtualMachineView(LoginRequiredMixin, View): | |||
|             email=owner.email, | ||||
|             password=owner.password | ||||
|         ) | ||||
| 
 | ||||
|         try: | ||||
|             vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data | ||||
|         terminated = manager.delete_vm( | ||||
|             vm.id | ||||
|         ) | ||||
|         except WrongIdError: | ||||
|             return redirect(reverse('hosting:virtual_machines')) | ||||
| 
 | ||||
|         terminated = manager.delete_vm(vm.id) | ||||
| 
 | ||||
|         if not terminated: | ||||
|             messages.error( | ||||
|                 request, | ||||
|                 'Error terminating VM %s' % (opennebula_vm_id) | ||||
|             ) | ||||
|             return HttpResponseRedirect(self.get_success_url()) | ||||
|             response['text'] = ugettext( | ||||
|                 'Error terminating VM') + opennebula_vm_id | ||||
|         else: | ||||
|             for t in range(15): | ||||
|                 try: | ||||
|                     manager.get_vm(opennebula_vm_id) | ||||
|                 except WrongIdError: | ||||
|                     response['status'] = True | ||||
|                     response['text'] = ugettext('Terminated') | ||||
|                     break | ||||
|                 except BaseException: | ||||
|                     break | ||||
|                 else: | ||||
|                     sleep(2) | ||||
|             context = { | ||||
|                 'vm': vm_data, | ||||
|                 'base_url': "{0}://{1}".format(self.request.scheme, | ||||
|  | @ -1036,15 +1064,11 @@ class VirtualMachineView(LoginRequiredMixin, View): | |||
|             } | ||||
|             email = BaseEmail(**email_data) | ||||
|             email.send() | ||||
| 
 | ||||
|         messages.error( | ||||
|             request, | ||||
|             _('VM %(VM_ID)s terminated successfully') % { | ||||
|                 'VM_ID': opennebula_vm_id} | ||||
|         return HttpResponse( | ||||
|             json.dumps(response), | ||||
|             content_type="application/json" | ||||
|         ) | ||||
| 
 | ||||
|         return HttpResponseRedirect(self.get_success_url()) | ||||
| 
 | ||||
| 
 | ||||
| class HostingBillListView(PermissionRequiredMixin, LoginRequiredMixin, | ||||
|                           ListView): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue