Commit 67ab8684 by Kálmán Viktor

Merge branch 'master' into feature-pipeline

Conflicts:
	circle/dashboard/static/dashboard/dashboard.js
	circle/dashboard/static/dashboard/disk-list.js
	circle/dashboard/static/dashboard/group-details.js
	circle/dashboard/static/dashboard/node-details.js
	circle/dashboard/static/dashboard/node-list.js
	circle/dashboard/static/dashboard/vm-details.js
	circle/dashboard/static/dashboard/vm-tour.js
	circle/dashboard/templates/dashboard/base.html
	circle/dashboard/templates/dashboard/index-nodes.html
	circle/dashboard/templates/dashboard/vm-detail.html
parents 368fa52f 387eb4e8
......@@ -23,6 +23,7 @@ celerybeat-schedule
.coverage
*,cover
coverage.xml
.noseids
# Gettext object file:
*.mo
......
......@@ -71,6 +71,17 @@ class AclBase(Model):
"""Define permission levels for Users/Groups per object."""
object_level_set = GenericRelation(ObjectLevel)
def clone_acl(self, other):
"""Clone full ACL from other object."""
assert self.id != other.id or type(self) != type(other)
self.object_level_set.clear()
for i in other.object_level_set.all():
ol = self.object_level_set.create(level=i.level)
for j in i.users.all():
ol.users.add(j)
for j in i.groups.all():
ol.groups.add(j)
@classmethod
def get_level_object(cls, level):
......@@ -229,7 +240,7 @@ class AclBase(Model):
levelfilter,
content_type=ct, level__weight__gte=level.weight).distinct()
clsfilter = Q(object_level_set__in=ols.all())
return cls.objects.filter(clsfilter)
return cls.objects.filter(clsfilter).distinct()
def save(self, *args, **kwargs):
super(AclBase, self).save(*args, **kwargs)
......
......@@ -514,9 +514,18 @@ LOGIN_REDIRECT_URL = "/"
AGENT_DIR = get_env_variable(
'DJANGO_AGENT_DIR', join(unicode(expanduser("~")), 'agent'))
# AGENT_DIR is the root directory for the agent.
# The directory structure SHOULD be:
# /home/username/agent
# |-- agent-linux
# | |-- .git
# | +-- ...
# |-- agent-win
# | +-- agent-win-%(version).exe
#
try:
git_env = {'GIT_DIR': join(AGENT_DIR, '.git')}
git_env = {'GIT_DIR': join(join(AGENT_DIR, "agent-linux"), '.git')}
AGENT_VERSION = check_output(
('git', 'log', '-1', r'--pretty=format:%h', 'HEAD'), env=git_env)
except:
......
......@@ -32,6 +32,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import (
CharField, DateTimeField, ForeignKey, NullBooleanField
)
from django.template import defaultfilters
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.functional import Promise
......@@ -48,7 +49,15 @@ class WorkerNotFound(Exception):
pass
def get_error_msg(exception):
try:
return unicode(exception)
except UnicodeDecodeError:
return unicode(str(exception), encoding='utf-8', errors='replace')
def activitycontextimpl(act, on_abort=None, on_commit=None):
result = None
try:
try:
yield act
......@@ -61,7 +70,7 @@ def activitycontextimpl(act, on_abort=None, on_commit=None):
result = create_readable(
ugettext_noop("Failure."),
ugettext_noop("Unhandled exception: %(error)s"),
error=unicode(e))
error=get_error_msg(e))
raise
except:
logger.exception("Failed activity %s" % unicode(act))
......@@ -428,6 +437,14 @@ class HumanReadableObject(object):
admin_text_template = admin_text_template._proxy____args[0]
self.user_text_template = user_text_template
self.admin_text_template = admin_text_template
for k, v in params.iteritems():
try:
v = timezone.datetime.strptime(
v, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.UTC())
except (ValueError, TypeError): # Mock raises TypeError
pass
if isinstance(v, timezone.datetime):
params[k] = defaultfilters.date(v, "DATETIME_FORMAT")
self.params = params
@classmethod
......@@ -444,24 +461,27 @@ class HumanReadableObject(object):
def from_dict(cls, d):
return None if d is None else cls(**d)
def get_admin_text(self):
if self.admin_text_template == "":
def _get_parsed_text(self, key):
value = getattr(self, key)
if value == "":
return ""
try:
return _(self.admin_text_template) % self.params
return _(value) % self.params
except KeyError:
logger.exception("Can't render %s '%s' %% %s",
key, value, unicode(self.params))
raise
def get_admin_text(self):
try:
return self._get_parsed_text("admin_text_template")
except KeyError:
logger.exception("Can't render admin_text_template '%s' %% %s",
self.admin_text_template, unicode(self.params))
return self.get_user_text()
def get_user_text(self):
if self.user_text_template == "":
return ""
try:
return _(self.user_text_template) % self.params
return self._get_parsed_text("user_text_template")
except KeyError:
logger.exception("Can't render user_text_template '%s' %% %s",
self.user_text_template, unicode(self.params))
return self.user_text_template
def get_text(self, user):
......
......@@ -26,6 +26,17 @@ from .models import activity_context, has_suffix, humanize_exception
logger = getLogger(__name__)
class SubOperationMixin(object):
required_perms = ()
def create_activity(self, parent, user, kwargs):
if not parent:
raise TypeError("SubOperation can only be called with "
"parent_activity specified.")
return super(SubOperationMixin, self).create_activity(
parent, user, kwargs)
class Operation(object):
"""Base class for VM operations.
"""
......@@ -36,6 +47,10 @@ class Operation(object):
abortable = False
has_percentage = False
@classmethod
def get_activity_code_suffix(cls):
return cls.id
def __call__(self, **kwargs):
return self.call(**kwargs)
......@@ -62,6 +77,8 @@ class Operation(object):
parent_activity = auxargs.pop('parent_activity')
if parent_activity and user is None and not skip_auth_check:
user = parent_activity.user
if user is None: # parent was a system call
skip_auth_check = True
# check for unexpected keyword arguments
argspec = getargspec(self._operation)
......@@ -232,7 +249,7 @@ class OperatedMixin(object):
operation could be found.
"""
for op in getattr(self, operation_registry_name, {}).itervalues():
if has_suffix(activity_code, op.activity_code_suffix):
if has_suffix(activity_code, op.get_activity_code_suffix()):
return op(self)
else:
return None
......
......@@ -22,6 +22,7 @@ from mock import MagicMock
from .models import TestClass
from ..models import HumanSortField
from ..models import activitycontextimpl
class MethodCacheTestCase(TestCase):
......@@ -80,3 +81,22 @@ class TestHumanSortField(TestCase):
test_result = HumanSortField.get_normalized_value(obj, val)
self.assertEquals(test_result, result)
class ActivityContextTestCase(TestCase):
class MyException(Exception):
pass
def test_unicode(self):
act = MagicMock()
gen = activitycontextimpl(act)
gen.next()
with self.assertRaises(self.MyException):
gen.throw(self.MyException(u'test\xe1'))
def test_str(self):
act = MagicMock()
gen = activitycontextimpl(act)
gen.next()
with self.assertRaises(self.MyException):
gen.throw(self.MyException('test\xbe'))
......@@ -27,9 +27,7 @@ class OperationTestCase(TestCase):
class AbortEx(Exception):
pass
op = Operation(MagicMock())
op.activity_code_suffix = 'test'
op.id = 'test'
op = TestOp(MagicMock())
op.async_operation = MagicMock(
apply_async=MagicMock(side_effect=AbortEx))
......@@ -44,9 +42,7 @@ class OperationTestCase(TestCase):
class AbortEx(Exception):
pass
op = Operation(MagicMock())
op.activity_code_suffix = 'test'
op.id = 'test'
op = TestOp(MagicMock())
with patch.object(Operation, 'create_activity', side_effect=AbortEx):
with patch.object(Operation, 'check_precond') as chk_pre:
try:
......@@ -55,9 +51,7 @@ class OperationTestCase(TestCase):
self.assertTrue(chk_pre.called)
def test_auth_check_on_non_system_call(self):
op = Operation(MagicMock())
op.activity_code_suffix = 'test'
op.id = 'test'
op = TestOp(MagicMock())
user = MagicMock()
with patch.object(Operation, 'check_auth') as check_auth:
with patch.object(Operation, 'check_precond'), \
......@@ -67,9 +61,7 @@ class OperationTestCase(TestCase):
check_auth.assert_called_with(user)
def test_no_auth_check_on_system_call(self):
op = Operation(MagicMock())
op.activity_code_suffix = 'test'
op.id = 'test'
op = TestOp(MagicMock())
with patch.object(Operation, 'check_auth', side_effect=AssertionError):
with patch.object(Operation, 'check_precond'), \
patch.object(Operation, 'create_activity'), \
......@@ -77,39 +69,25 @@ class OperationTestCase(TestCase):
op.call(system=True)
def test_no_exception_for_more_arguments_when_operation_takes_kwargs(self):
class KwargOp(Operation):
activity_code_suffix = 'test'
id = 'test'
def _operation(self, **kwargs):
pass
op = KwargOp(MagicMock())
with patch.object(KwargOp, 'create_activity'), \
patch.object(KwargOp, '_exec_op'):
op = TestOp(MagicMock())
with patch.object(TestOp, 'create_activity'), \
patch.object(TestOp, '_exec_op'):
op.call(system=True, foo=42)
def test_exception_for_unexpected_arguments(self):
class TestOp(Operation):
activity_code_suffix = 'test'
id = 'test'
def _operation(self):
pass
op = TestOp(MagicMock())
with patch.object(TestOp, 'create_activity'), \
patch.object(TestOp, '_exec_op'):
self.assertRaises(TypeError, op.call, system=True, foo=42)
self.assertRaises(TypeError, op.call, system=True, bar=42)
def test_exception_for_missing_arguments(self):
class TestOp(Operation):
activity_code_suffix = 'test'
op = TestOp(MagicMock())
with patch.object(TestOp, 'create_activity'):
self.assertRaises(TypeError, op.call, system=True)
class TestOp(Operation):
id = 'test'
def _operation(self, foo):
pass
op = TestOp(MagicMock())
with patch.object(TestOp, 'create_activity'):
self.assertRaises(TypeError, op.call, system=True)
......@@ -236,6 +236,9 @@ class GroupProfile(AclBase):
help_text=_('Unique identifier of the group at the organization.'))
description = TextField(blank=True)
def __unicode__(self):
return self.group.name
def save(self, *args, **kwargs):
if not self.org_id:
self.org_id = None
......
......@@ -411,13 +411,24 @@ $(function () {
$(this).removeClass("btn-default").addClass("btn-primary");
return false;
});
// vm migrate select for node
$(document).on("click", "#vm-migrate-node-list li", function(e) {
var li = $(this).closest('li');
if (li.find('input').attr('disabled'))
return true;
$('#vm-migrate-node-list li').removeClass('panel-primary');
li.addClass('panel-primary').find('input').prop("checked", true);
return true;
});
});
function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
return '<a href="/dashboard/vm/' + pk + '/" class="list-group-item' +
(is_last ? ' list-group-item-last' : '') + '">' +
'<span class="index-vm-list-name">' +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + name +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + safe_tags_replace(name) +
'</span>' +
'<small class="text-muted"> ' + host + '</small>' +
'<div class="pull-right dashboard-vm-favourite" data-vm="' + pk + '">' +
......@@ -430,14 +441,14 @@ function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
function generateGroupHTML(url, name, is_last) {
return '<a href="' + url + '" class="list-group-item real-link' + (is_last ? " list-group-item-last" : "") +'">'+
'<i class="fa fa-users"></i> '+ name +
'<i class="fa fa-users"></i> '+ safe_tags_replace(name) +
'</a>';
}
function generateNodeHTML(name, icon, _status, url, is_last) {
return '<a href="' + url + '" class="list-group-item real-link' + (is_last ? ' list-group-item-last' : '') + '">' +
'<span class="index-node-list-name">' +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + name +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + safe_tags_replace(name) +
'</span>' +
'<div style="clear: both;"></div>' +
'</a>';
......@@ -445,7 +456,7 @@ function generateNodeHTML(name, icon, _status, url, is_last) {
function generateNodeTagHTML(name, icon, _status, label , url) {
return '<a href="' + url + '" class="label ' + label + '" >' +
'<i class="' + icon + '" title="' + _status + '"></i> ' + name +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + safe_tags_replace(name) +
'</a> ';
}
......@@ -619,7 +630,7 @@ function addModalConfirmation(func, data) {
}
function clientInstalledAction(location) {
setCookie('downloaded_client', true, 365 * 24 * 60 * 60, "/");
setCookie('downloaded_client', true, 365 * 24 * 60 * 60 * 1000, "/");
window.location.href = location;
$('#confirmation-modal').modal("hide");
}
......@@ -687,3 +698,17 @@ $(function() {
return choice.children().html();
}
});
var tagsToReplace = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;'
};
function replaceTag(tag) {
return tagsToReplace[tag] || tag;
}
function safe_tags_replace(str) {
return str.replace(/[&<>]/g, replaceTag);
}
......@@ -216,7 +216,7 @@ html {
}
#vm-list-rename-name, #node-list-rename-name, #group-list-rename-name {
max-width: 100px;
max-width: 150px;
}
.label-tag {
......@@ -539,7 +539,7 @@ footer a, footer a:hover, footer a:visited {
}
#dashboard-template-list a small {
max-width: 50%;
max-width: 45%;
float: left;
padding-top: 2px;
text-overflow: ellipsis;
......@@ -699,7 +699,7 @@ textarea[name="new_members"] {
.dashboard-vm-details-connect-command {
/* for mobile view */
margin-bottom: 20px;
padding-bottom: 20px;
}
#store-list-list {
......@@ -1014,6 +1014,14 @@ textarea[name="new_members"] {
cursor: pointer
}
#vm-details-resources-disk {
padding: 2px 5px 10px 5px;
}
#vm-details-start-template-tour {
margin-right: 5px;
}
#vm-activity-state {
margin-bottom: 15px;
}
......@@ -1027,6 +1035,24 @@ textarea[name="new_members"] {
color: orange;
}
.introjs-skipbutton {
color: #333;
}
.introjs-button:focus {
text-decoration: none;
color: #333;
outline: none;
}
.introjs-button:hover:not(.introjs-disabled) {
color: #428bca;
}
.introjs-tooltip {
min-width: 250px;
}
#vm-info-pane {
margin-bottom: 20px;
}
......@@ -1053,7 +1079,8 @@ textarea[name="new_members"] {
max-width: 100%;
}
#vm-list-table tbody td:nth-child(3) {
#vm-list-table td.state,
#vm-list-table td.memory {
white-space: nowrap;
}
......@@ -1064,3 +1091,16 @@ textarea[name="new_members"] {
.disk-resize-btn {
margin-right: 5px;
}
#vm-migrate-node-list li {
cursor: pointer;
}
.group-list-table .actions,
.group-list-table .admin,
.group-list-table .number_of_users,
.group-list-table .pk {
width: 1px;
white-space: nowrap;
text-align: center;
}
$(function() {
$(".disk-list-disk-percentage").each(function() {
var disk = $(this).data("disk-pk");
var element = $(this);
refreshDisk(disk, element);
});
});
function refreshDisk(disk, element) {
$.get("/dashboard/disk/" + disk + "/status/", function(result) {
if(result.percentage === null || result.failed == "True") {
location.reload();
} else {
var diff = result.percentage - parseInt(element.html());
var refresh = 5 - diff;
refresh = refresh < 1 ? 1 : (result.percentage === 0 ? 1 : refresh);
if(isNaN(refresh)) refresh = 2; // this should not happen
element.html(result.percentage);
setTimeout(function() {refreshDisk(disk, element);}, refresh * 1000);
}
});
}
......@@ -14,7 +14,7 @@
data: {'new_name': name},
headers: {"X-CSRFToken": getCookie('csrftoken')},
success: function(data, textStatus, xhr) {
$("#group-details-h1-name").html(data.new_name).show();
$("#group-details-h1-name").text(data['new_name']).show();
$('#group-details-rename').hide();
// addMessage(data['message'], "success");
},
......
......@@ -3,6 +3,7 @@ $(function() {
$("#group-list-rename-button, .group-details-rename-button").click(function() {
$("#group-list-column-name", $(this).closest("tr")).hide();
$("#group-list-rename", $(this).closest("tr")).css('display', 'inline');
$("#group-list-rename").find("input").select();
});
/* rename ajax */
......
.introjs-overlay{position:absolute;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));background:-webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1);-ms-filter:"alpha(opacity=50)";filter:alpha(opacity=50);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto !important;opacity:1.0 !important}.introjs-showElement,tr.introjs-showElement>td,tr.introjs-showElement>th{z-index:9999999 !important}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperNumberLayer{position:absolute;top:-16px;left:-16px;z-index:9999999999 !important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019',endColorstr='#cf0404',GradientType=0);filter:progid:DXImageTransform.Microsoft.Shadow(direction=135,strength=2,color=ff0000);box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-right{top:-10px;right:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{position:absolute;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right}.introjs-button{position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-bullets{text-align:center}.introjs-bullets ul{clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%}
.introjs-helperLayer *,
.introjs-helperLayer *:before,
.introjs-helperLayer *:after {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
-ms-box-sizing: content-box;
-o-box-sizing: content-box;
box-sizing: content-box;
}
......@@ -15,7 +15,7 @@ $(function() {
data: {'new_name': name},
headers: {"X-CSRFToken": getCookie('csrftoken')},
success: function(data, textStatus, xhr) {
$("#node-details-h1-name").html(data.new_name).show();
$("#node-details-h1-name").text(data['new_name']).show();
$('#node-details-rename').hide();
// addMessage(data.message, "success");
},
......
......@@ -10,41 +10,6 @@ $(function() {
$('.true').closest("tr").removeClass('danger');
}
/* rename */
$("#node-list-rename-button, .node-details-rename-button").click(function() {
$("#node-list-column-name", $(this).closest("tr")).hide();
$("#node-list-rename", $(this).closest("tr")).css('display', 'inline');
});
/* rename ajax */
$('.node-list-rename-submit').click(function() {
var row = $(this).closest("tr");
var name = $('#node-list-rename-name', row).val();
var url = '/dashboard/node/' + 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) {
$("#node-list-column-name", row).html(
$("<a/>", {
'class': "real-link",
href: "/dashboard/node/" + data.node_pk + "/",
text: data.new_name
})
).show();
$('#node-list-rename', row).hide();
// addMessage(data['message'], "success");
},
error: function(xhr, textStatus, error) {
addMessage("Error during renaming!", "danger");
}
});
return false;
});
function statuschangeSuccess(tr){
var tspan=tr.children('.enabled').children();
var buttons=tr.children('.actions').children('.btn-group').children('.dropdown-menu').children('li').children('.node-enable');
......
......@@ -2,7 +2,7 @@ $(function() {
/* for template removes buttons */
$('.template-delete').click(function() {
var template_pk = $(this).data('template-pk');
addModalConfirmation(deleteTemplate,
addModalConfirmationOrDisplayMessage(deleteTemplate,
{ 'url': '/dashboard/template/delete/' + template_pk + '/',
'data': [],
'template_pk': template_pk,
......@@ -13,7 +13,7 @@ $(function() {
/* for lease removes buttons */
$('.lease-delete').click(function() {
var lease_pk = $(this).data('lease-pk');
addModalConfirmation(deleteLease,
addModalConfirmationOrDisplayMessage(deleteLease,
{ 'url': '/dashboard/lease/delete/' + lease_pk + '/',
'data': [],
'lease_pk': lease_pk,
......@@ -81,3 +81,29 @@ function deleteLease(data) {
}
});
}
function addModalConfirmationOrDisplayMessage(func, data) {
$.ajax({
type: 'GET',
url: data['url'],
data: jQuery.param(data['data']),
success: function(result) {
$('body').append(result);
$('#confirmation-modal').modal('show');
$('#confirmation-modal').on('hidden.bs.modal', function() {
$('#confirmation-modal').remove();
});
$('#confirmation-modal-button').click(function() {
func(data);
$('#confirmation-modal').modal('hide');
});
},
error: function(xhr, textStatus, error) {
if(xhr.status === 403) {
addMessage(gettext("Only the owners can delete the selected object."), "warning");
} else {
addMessage(gettext("An error occurred. (") + xhr.status + ")", 'danger')
}
}
});
}
......@@ -16,19 +16,10 @@ $(function() {
$('#confirmation-modal').on('hidden.bs.modal', function() {
$('#confirmation-modal').remove();
});
$('#vm-migrate-node-list li').click(function(e) {
var li = $(this).closest('li');
if (li.find('input').attr('disabled'))
return true;
$('#vm-migrate-node-list li').removeClass('panel-primary');
li.addClass('panel-primary').find('input').attr('checked', true);
return false;
});
$('#vm-migrate-node-list li input:checked').closest('li').addClass('panel-primary');
}
});
return false;
e.preventDefault();
});
/* if the operation fails show the modal again */
......@@ -51,7 +42,8 @@ $(function() {
if(data.success) {
$('a[href="#activity"]').trigger("click");
if(data.with_reload) {
location.reload();
// when the activity check stops the page will reload
reload_vm_detail = true;
}
/* if there are messages display them */
......
var show_all = false;
var in_progress = false;
var activity_hash = 5;
var Websock_native;
var Websock_native; // not sure
var reload_vm_detail = false;