Commit cce7935c by Őry Máté

Merge branch 'feature-opview-retouch' into 'master'

Retouch operation buttons
parents ff62083a b77be59b
...@@ -2,10 +2,20 @@ ...@@ -2,10 +2,20 @@
{% for op in ops %} {% for op in ops %}
{% if op.show_in_toolbar %} {% if op.show_in_toolbar %}
<a href="{{op.get_url}}" class="operation operation-{{op.op}} btn btn-default btn-xs"
title="{{op.name}}: {{op.description}}"> {% if op.disabled %}
<span class="operation operation-{{op.op}} btn btn-{{op.effect}} disabled btn-xs">
{% else %}
<a href="{{op.get_url}}" class="operation operation-{{op.op}} btn
btn-{{op.effect}} btn-xs" title="{{op.name}}: {{op.description}}">
{% endif %}
<i class="icon-{{op.icon}}"></i> <i class="icon-{{op.icon}}"></i>
<span class="sr-only">{{op.name}}</span> <span{% if not op.is_preferred %} class="sr-only"{% endif %}>{{op.name}}</span>
{% if op.disabled %}
</span>
{% else %}
</a> </a>
{% endif %} {% endif %}
{% endif %}
{% endfor %} {% endfor %}
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
from collections import OrderedDict
from itertools import chain from itertools import chain
from os import getenv from os import getenv
import json import json
...@@ -525,6 +526,7 @@ class OperationView(DetailView): ...@@ -525,6 +526,7 @@ class OperationView(DetailView):
template_name = 'dashboard/operate.html' template_name = 'dashboard/operate.html'
show_in_toolbar = True show_in_toolbar = True
effect = None
@property @property
def name(self): def name(self):
...@@ -534,6 +536,9 @@ class OperationView(DetailView): ...@@ -534,6 +536,9 @@ class OperationView(DetailView):
def description(self): def description(self):
return self.get_op().description return self.get_op().description
def is_preferred(self):
return self.get_op().is_preferred()
@classmethod @classmethod
def get_urlname(cls): def get_urlname(cls):
return 'dashboard.vm.op.%s' % cls.op return 'dashboard.vm.op.%s' % cls.op
...@@ -583,14 +588,16 @@ class OperationView(DetailView): ...@@ -583,14 +588,16 @@ class OperationView(DetailView):
return redirect("%s#activity" % self.object.get_absolute_url()) return redirect("%s#activity" % self.object.get_absolute_url())
@classmethod @classmethod
def factory(cls, op, icon='cog'): def factory(cls, op, icon='cog', effect='info'):
return type(str(cls.__name__ + op), return type(str(cls.__name__ + op),
(cls, ), {'op': op, 'icon': icon}) (cls, ), {'op': op, 'icon': icon, 'effect': effect})
@classmethod @classmethod
def bind_to_object(cls, instance): def bind_to_object(cls, instance, **kwargs):
v = cls() v = cls()
v.get_object = lambda: instance v.get_object = lambda: instance
for key, value in kwargs.iteritems():
setattr(v, key, value)
return v return v
...@@ -666,6 +673,7 @@ class VmMigrateView(VmOperationView): ...@@ -666,6 +673,7 @@ class VmMigrateView(VmOperationView):
op = 'migrate' op = 'migrate'
icon = 'truck' icon = 'truck'
effect = 'info'
template_name = 'dashboard/_vm-migrate.html' template_name = 'dashboard/_vm-migrate.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
...@@ -688,22 +696,31 @@ class VmSaveView(FormOperationMixin, VmOperationView): ...@@ -688,22 +696,31 @@ class VmSaveView(FormOperationMixin, VmOperationView):
op = 'save_as_template' op = 'save_as_template'
icon = 'save' icon = 'save'
effect = 'info'
form_class = VmSaveForm form_class = VmSaveForm
vm_ops = { vm_ops = OrderedDict([
'reset': VmOperationView.factory(op='reset', icon='bolt'), ('deploy', VmOperationView.factory(
'deploy': VmOperationView.factory(op='deploy', icon='play'), op='deploy', icon='play', effect='success')),
'migrate': VmMigrateView, ('wake_up', VmOperationView.factory(
'reboot': VmOperationView.factory(op='reboot', icon='refresh'), op='wake_up', icon='sun', effect='success')),
'shut_off': VmOperationView.factory(op='shut_off', icon='ban-circle'), ('sleep', VmOperationView.factory(
'shutdown': VmOperationView.factory(op='shutdown', icon='off'), op='sleep', icon='moon', effect='info')),
'save_as_template': VmSaveView, ('migrate', VmMigrateView),
'destroy': VmOperationView.factory(op='destroy', icon='remove'), ('save_as_template', VmSaveView),
'sleep': VmOperationView.factory(op='sleep', icon='moon'), ('reboot', VmOperationView.factory(
'wake_up': VmOperationView.factory(op='wake_up', icon='sun'), op='reboot', icon='refresh', effect='warning')),
'create_disk': VmCreateDiskView, ('reset', VmOperationView.factory(
'download_disk': VmDownloadDiskView, op='reset', icon='bolt', effect='warning')),
} ('shutdown', VmOperationView.factory(
op='shutdown', icon='off', effect='warning')),
('shut_off', VmOperationView.factory(
op='shut_off', icon='ban-circle', effect='warning')),
('destroy', VmOperationView.factory(
op='destroy', icon='remove', effect='danger')),
('create_disk', VmCreateDiskView),
('download_disk', VmDownloadDiskView),
])
def get_operations(instance, user): def get_operations(instance, user):
...@@ -713,9 +730,11 @@ def get_operations(instance, user): ...@@ -713,9 +730,11 @@ def get_operations(instance, user):
op = v.get_op_by_object(instance) op = v.get_op_by_object(instance)
op.check_auth(user) op.check_auth(user)
op.check_precond() op.check_precond()
except Exception as e: except PermissionDenied as e:
logger.debug('Not showing operation %s for %s: %s', logger.debug('Not showing operation %s for %s: %s',
k, instance, unicode(e)) k, instance, unicode(e))
except Exception:
ops.append(v.bind_to_object(instance, disabled=True))
else: else:
ops.append(v.bind_to_object(instance)) ops.append(v.bind_to_object(instance))
return ops return ops
......
...@@ -75,6 +75,11 @@ class InstanceOperation(Operation): ...@@ -75,6 +75,11 @@ class InstanceOperation(Operation):
code_suffix=self.activity_code_suffix, instance=self.instance, code_suffix=self.activity_code_suffix, instance=self.instance,
user=user) user=user)
def is_preferred(self):
"""If this is the recommended op in the current state of the instance.
"""
return False
class AddInterfaceOperation(InstanceOperation): class AddInterfaceOperation(InstanceOperation):
activity_code_suffix = 'add_interface' activity_code_suffix = 'add_interface'
...@@ -154,6 +159,10 @@ class DeployOperation(InstanceOperation): ...@@ -154,6 +159,10 @@ class DeployOperation(InstanceOperation):
name = _("deploy") name = _("deploy")
description = _("Deploy new virtual machine with network.") description = _("Deploy new virtual machine with network.")
def is_preferred(self):
return self.instance.status in (self.instance.STATUS.STOPPED,
self.instance.STATUS.ERROR)
def on_commit(self, activity): def on_commit(self, activity):
activity.resultant_state = 'RUNNING' activity.resultant_state = 'RUNNING'
...@@ -337,6 +346,10 @@ class SaveAsTemplateOperation(InstanceOperation): ...@@ -337,6 +346,10 @@ class SaveAsTemplateOperation(InstanceOperation):
""") """)
abortable = True abortable = True
def is_preferred(self):
return (self.instance.is_base and
self.instance.status == self.instance.STATUS.RUNNING)
@staticmethod @staticmethod
def _rename(name): def _rename(name):
m = search(r" v(\d+)$", name) m = search(r" v(\d+)$", name)
...@@ -472,6 +485,10 @@ class SleepOperation(InstanceOperation): ...@@ -472,6 +485,10 @@ class SleepOperation(InstanceOperation):
name = _("sleep") name = _("sleep")
description = _("Suspend virtual machine with memory dump.") description = _("Suspend virtual machine with memory dump.")
def is_preferred(self):
return (not self.instance.is_base and
self.instance.status == self.instance.STATUS.RUNNING)
def check_precond(self): def check_precond(self):
super(SleepOperation, self).check_precond() super(SleepOperation, self).check_precond()
if self.instance.status not in ['RUNNING']: if self.instance.status not in ['RUNNING']:
...@@ -511,6 +528,10 @@ class WakeUpOperation(InstanceOperation): ...@@ -511,6 +528,10 @@ class WakeUpOperation(InstanceOperation):
Power on Virtual Machine and load its memory from dump. Power on Virtual Machine and load its memory from dump.
""") """)
def is_preferred(self):
return (self.instance.is_base and
self.instance.status == self.instance.STATUS.SUSPENDED)
def check_precond(self): def check_precond(self):
super(WakeUpOperation, self).check_precond() super(WakeUpOperation, self).check_precond()
if self.instance.status not in ['SUSPENDED']: if self.instance.status not in ['SUSPENDED']:
......
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