Commit de54bc3b by Őry Máté

Merge branch 'issue-sliders' into 'master'

VM resources sliders

 new sliders from VM detail
 new sliders from VM customized create
  configurable max node ram
 server side max node ram check
 new sliders for template edit/create

https://miskolc.cloud.bme.hu:18525/dashboard/

Closes #183
Closes #137
parents 1ee2b455 7bdefb89
......@@ -458,3 +458,5 @@ STORE_URL = get_env_variable("STORE_URL", "")
SESSION_COOKIE_NAME = "csessid%x" % (((getnode() // 139) ^
(getnode() % 983)) & 0xffff)
MAX_NODE_RAM = get_env_variable("MAX_NODE_RAM", 1024)
......@@ -420,6 +420,7 @@ create_readable = HumanReadableObject.create
class HumanReadableException(HumanReadableObject, Exception):
"""HumanReadableObject that is an Exception so can used in except clause.
"""
def __init__(self, level=None, *args, **kwargs):
super(HumanReadableException, self).__init__(*args, **kwargs)
if level is not None:
......@@ -450,6 +451,7 @@ def humanize_exception(message, exception=None, level=None, **params):
...
Welcome!
"""
Ex = type("HumanReadable" + type(exception).__name__,
(HumanReadableException, type(exception)),
exception.__dict__)
......
......@@ -1382,7 +1382,7 @@
"pw": "ads",
"time_of_suspend": null,
"ram_size": 200,
"priority": 4,
"priority": 10,
"active_since": null,
"template": null,
"access_method": "nx",
......@@ -1412,7 +1412,7 @@
"pw": "ads",
"time_of_suspend": null,
"ram_size": 200,
"priority": 4,
"priority": 10,
"active_since": null,
"template": null,
"access_method": "nx",
......@@ -1518,7 +1518,7 @@
"ram_size": 1024,
"modified": "2014-01-24T00:58:19.654Z",
"system": "bubuntu",
"priority": 20,
"priority": 10,
"access_method": "ssh",
"raw_data": "",
"arch": "x86_64",
......
......@@ -186,42 +186,6 @@ html {
text-decoration: none !important;
}
.slider {
display: inline-block;
}
.slider .track {
height: 20px;
top: 50%;
}
.slider > .dragger, .slider > .dragger:hover {
border-radius: 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
width: 8px;
height: 24px;
margin-top: -12px!important;
text-shadow: 0 1px 0 #fff;
background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
background-repeat: repeat-x;
border-color: #2d6ca2;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
}
.slider > .dragger:hover {
background-color: #3071a9;
background-image: none;
border-color: #2d6ca2;
}
.slider > .highlight-track {
height: 20px;
top: 50%;
}
.slider + .output {
}
.rule-table tr >:nth-child(1) {
text-align: right;
}
......@@ -848,3 +812,54 @@ textarea[name="list-new-namelist"] {
#show-all-activities-container {
margin: 20px 0 0 10px;
}
#vm-details-resources-form {
margin-top: 15px;
}
#vm-details-resources-form .row, .resources-sliders .row {
margin-bottom: 15px;
}
#vm-create-disk-add-form {
max-width: 450px;
margin-top: 15px;
}
.vm-create-template {
max-width: 800px;
border: 1px solid black;
border-bottom: none;
}
.vm-create-template-list .vm-create-template:last-child {
border-bottom: 1px solid black;
}
.vm-create-template-summary {
padding: 15px;
cursor: pointer;
}
.vm-create-template:nth-child(odd) .vm-create-template-summary {
background: #F5F5F5;
}
.vm-create-template-list .vm-create-template-summary:hover {
background: #D2D2D2;
}
.vm-create-template-details {
border-top: 1px dashed #D3D3D3;
padding: 15px;
}
.vm-create-template-details ul {
list-style: none;
padding: 0 15px;
}
.vm-create-template-details li {
border-bottom: 1px dotted #aaa;
padding: 5px 0px;
}
......@@ -435,28 +435,63 @@ function compareVmByFav(a, b) {
return a.pk < b.pk ? -1 : 1;
}
$(document).on('shown.bs.tab', 'a[href="#resources"]', function (e) {
$(".cpu-priority-input").trigger("change");
$(".cpu-count-input, .ram-input").trigger("input");
})
function addSliderMiscs() {
$('.vm-slider').each(function() {
$("<span>").addClass("output").html($(this).val()).insertAfter($(this));
});
$('.vm-slider').slider()
.on('slide', function(e) {
$(this).val(e.value);
$(this).parent('div').nextAll("span").html(e.value)
// set max values based on inputs
var cpu_count_range = "0, " + $(".cpu-count-input").prop("max");
var ram_range = "0, " + $(".ram-input").prop("max");
$(".cpu-count-slider").data("slider-range", cpu_count_range);
$(".ram-slider").data("slider-range", ram_range);
$(".vm-slider").simpleSlider();
$(".cpu-priority-slider").bind("slider:changed", function (event, data) {
var value = data.value + 0;
$('.cpu-priority-input option[value="' + value + '"]').attr("selected", "selected");
});
refreshSliders();
}
$(".cpu-priority-input").change(function() {
var val = $(":selected", $(this)).val();
$(".cpu-priority-slider").simpleSlider("setValue", val);
});
$(".cpu-count-slider").bind("slider:changed", function (event, data) {
var value = data.value + 0;
$(".cpu-count-input").val(parseInt(value));
});
// ehhh
function refreshSliders() {
$('.vm-slider').each(function() {
$(this).val($(this).slider().data('slider').getValue());
$(this).parent('div').nextAll("span").html($(this).val());
$(".cpu-count-input").bind("input", function() {
var val = parseInt($(this).val());
if(!val) return;
$(".cpu-count-slider").simpleSlider("setValue", val);
});
var ram_fire = false;
$(".ram-slider").bind("slider:changed", function (event, data) {
if(ram_fire) {
ram_fire = false;
return;
}
var value = data.value + 0;
$(".ram-input").val(value);
});
$(".ram-input").bind("input", function() {
var val = $(this).val();
ram_fire = true;
$(".ram-slider").simpleSlider("setValue", parseInt(val));
});
$(".cpu-priority-input").trigger("change");
$(".cpu-count-input, .ram-input").trigger("input");
}
/* deletes the VM with the pk
* if dir is true, then redirect to the dashboard landing page
* else it adds a success message */
......
jQuery Simple Slider: Unobtrusive Numerical Slider
==================================================
SimpleSlider is a jQuery plugin for turning your text inputs into draggable
numerical sliders.
It has no external dependencies other than jQuery, and you don't need to write
a single line of JavaScript to get it to work.
How to Use
-----------
Include the javascript file in your page:
<script src="simple-slider.js"></script>
Turn your text input into a slider:
<input type="text" data-slider="true">
Documentation, Features and Demos
---------------------------------
Full details and documentation can be found on the project page here:
<http://loopj.com/jquery-simple-slider/>
\ No newline at end of file
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="js/simple-slider.js"></script>
<link href="css/simple-slider.css" rel="stylesheet" type="text/css" />
<link href="css/simple-slider-volume.css" rel="stylesheet" type="text/css" />
<!-- These styles are only used for this page, not required for the slider -->
<style>
body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
[class^=slider] { display: inline-block; margin-bottom: 30px; }
.output { color: #888; font-size: 14px; padding-top: 1px; margin-left: 5px; vertical-align: top;}
h1 { font-size: 20px; }
h2 { clear: both; margin: 0; margin-bottom: 5px; font-size: 16px; }
p { font-size: 15px; margin-bottom: 30px; }
h2:first-of-type { margin-top: 0; }
</style>
</head>
<body>
<h1>jQuery Simple Slider Examples</h1>
<p>
Here are a few examples of the functionality available in Simple Slider.
</p>
<h2>Basic Example</h2>
<input type="text" data-slider="true">
<h2>Basic Example (Themed)</h2>
<input type="text" data-slider="true" data-slider-theme="volume">
<h2>Predefined Value</h2>
<input type="text" value="0.2" data-slider="true">
<h2>Steps</h2>
<input type="text" data-slider="true" data-slider-step="0.1">
<h2>Range</h2>
<input type="text" data-slider="true" data-slider-range="10,1000">
<h2>Range &amp; Steps</h2>
<input type="text" data-slider="true" data-slider-range="100,500" data-slider-step="100">
<h2>Range, Steps &amp; Snap</h2>
<input type="text" data-slider="true" data-slider-range="100,500" data-slider-step="100" data-slider-snap="true">
<h2>Predefined List of Values</h2>
<input type="text" data-slider="true" data-slider-values="0,100,500,800,2000">
<h2>Predefined List &amp; Snap</h2>
<input type="text" data-slider="true" data-slider-values="0,100,500,800,2000" data-slider-snap="true">
<h2>Predefined List, Equal Steps &amp; Snap</h2>
<input type="text" data-slider="true" data-slider-values="0,100,500,800,2000" data-slider-equal-steps="true" data-slider-snap="true">
<h2>Highlighted</h2>
<input type="text" data-slider="true" value="0.8" data-slider-highlight="true">
<h2>Highlighted (Themed)</h2>
<input type="text" data-slider="true" value="0.4" data-slider-highlight="true" data-slider-theme="volume">
<script>
$("[data-slider]")
.each(function () {
var input = $(this);
$("<span>")
.addClass("output")
.insertAfter($(this));
})
.bind("slider:ready slider:changed", function (event, data) {
$(this)
.nextAll(".output:first")
.html(data.value.toFixed(3));
});
</script>
</body>
</html>
module.exports = function(grunt) {
grunt.initConfig({
pkg: '<json:package.json>',
meta: {
banner:
'/*\n' +
' * <%= pkg.title || pkg.name %>: <%= pkg.description %>\n' +
' * Version <%= pkg.version %>\n' +
' *\n' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> (<%= pkg.author.url %>)\n' +
' *\n' +
' * Licensed under the <%= pkg.licenses[0].type %> license (<%= pkg.licenses[0].url %>)\n' +
' *\n' +
' */\n'
},
coffee: {
compile: {
files: {
'js/<%= pkg.name %>.js': 'js/*.coffee'
},
options: {
bare: true
}
}
},
watch: {
coffee: {
files: ['js/*.coffee'],
tasks: 'coffee growl:coffee'
}
},
growl: {
coffee: {
title: 'CoffeeScript',
message: 'Compiled successfully'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', 'js/<%= pkg.name %>.js'],
dest: 'js/<%= pkg.name %>.min.js'
}
},
compress: {
zip: {
files: {
"<%= pkg.name %>-<%= pkg.version %>.zip": ["js/**", "demo.html", "README.md"]
}
}
}
});
// Lib tasks.
grunt.loadNpmTasks('grunt-contrib');
grunt.loadNpmTasks('grunt-growl');
// Default task.
grunt.registerTask('build', 'coffee min');
grunt.registerTask('serve', 'server watch:coffee');
grunt.registerTask('default', 'build');
};
\ No newline at end of file
/*
* jQuery Simple Slider: Unobtrusive Numerical Slider
* Version 1.0.0
*
* Copyright (c) 2013 James Smith (http://loopj.com)
*
* Licensed under the MIT license (http://mit-license.org/)
*
*/
var __slice=[].slice,__indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++)if(t in this&&this[t]===e)return t;return-1};(function(e,t){var n;return n=function(){function t(t,n){var r,i=this;this.input=t,this.defaultOptions={animate:!0,snapMid:!1,classPrefix:null,classSuffix:null,theme:null,highlight:!1},this.settings=e.extend({},this.defaultOptions,n),this.settings.theme&&(this.settings.classSuffix="-"+this.settings.theme),this.input.hide(),this.slider=e("<div>").addClass("slider"+(this.settings.classSuffix||"")).css({position:"relative",userSelect:"none",boxSizing:"border-box"}).insertBefore(this.input),this.input.attr("id")&&this.slider.attr("id",this.input.attr("id")+"-slider"),this.track=this.createDivElement("track").css({width:"100%"}),this.settings.highlight&&(this.highlightTrack=this.createDivElement("highlight-track").css({width:"0"})),this.dragger=this.createDivElement("dragger"),this.slider.css({minHeight:this.dragger.outerHeight(),marginLeft:this.dragger.outerWidth()/2,marginRight:this.dragger.outerWidth()/2}),this.track.css({marginTop:this.track.outerHeight()/-2}),this.settings.highlight&&this.highlightTrack.css({marginTop:this.track.outerHeight()/-2}),this.dragger.css({marginTop:this.dragger.outerWidth()/-2,marginLeft:this.dragger.outerWidth()/-2}),this.track.mousedown(function(e){return i.trackEvent(e)}),this.settings.highlight&&this.highlightTrack.mousedown(function(e){return i.trackEvent(e)}),this.dragger.mousedown(function(e){if(e.which!==1)return;return i.dragging=!0,i.dragger.addClass("dragging"),i.domDrag(e.pageX,e.pageY),!1}),e("body").mousemove(function(t){if(i.dragging)return i.domDrag(t.pageX,t.pageY),e("body").css({cursor:"pointer"})}).mouseup(function(t){if(i.dragging)return i.dragging=!1,i.dragger.removeClass("dragging"),e("body").css({cursor:"auto"})}),this.pagePos=0,this.input.val()===""?(this.value=this.getRange().min,this.input.val(this.value)):this.value=this.nearestValidValue(this.input.val()),this.setSliderPositionFromValue(this.value),r=this.valueToRatio(this.value),this.input.trigger("slider:ready",{value:this.value,ratio:r,position:r*this.slider.outerWidth(),el:this.slider})}return t.prototype.createDivElement=function(t){var n;return n=e("<div>").addClass(t).css({position:"absolute",top:"50%",userSelect:"none",cursor:"pointer"}).appendTo(this.slider),n},t.prototype.setRatio=function(e){var t;return e=Math.min(1,e),e=Math.max(0,e),t=this.ratioToValue(e),this.setSliderPositionFromValue(t),this.valueChanged(t,e,"setRatio")},t.prototype.setValue=function(e){var t;return e=this.nearestValidValue(e),t=this.valueToRatio(e),this.setSliderPositionFromValue(e),this.valueChanged(e,t,"setValue")},t.prototype.trackEvent=function(e){if(e.which!==1)return;return this.domDrag(e.pageX,e.pageY,!0),this.dragging=!0,!1},t.prototype.domDrag=function(e,t,n){var r,i,s;n==null&&(n=!1),r=e-this.slider.offset().left,r=Math.min(this.slider.outerWidth(),r),r=Math.max(0,r);if(this.pagePos!==r)return this.pagePos=r,i=r/this.slider.outerWidth(),s=this.ratioToValue(i),this.valueChanged(s,i,"domDrag"),this.settings.snap?this.setSliderPositionFromValue(s,n):this.setSliderPosition(r,n)},t.prototype.setSliderPosition=function(e,t){t==null&&(t=!1);if(t&&this.settings.animate){this.dragger.animate({left:e},200);if(this.settings.highlight)return this.highlightTrack.animate({width:e},200)}else{this.dragger.css({left:e});if(this.settings.highlight)return this.highlightTrack.css({width:e})}},t.prototype.setSliderPositionFromValue=function(e,t){var n;return t==null&&(t=!1),n=this.valueToRatio(e),this.setSliderPosition(n*this.slider.outerWidth(),t)},t.prototype.getRange=function(){return this.settings.allowedValues?{min:Math.min.apply(Math,this.settings.allowedValues),max:Math.max.apply(Math,this.settings.allowedValues)}:this.settings.range?{min:parseFloat(this.settings.range[0]),max:parseFloat(this.settings.range[1])}:{min:0,max:1}},t.prototype.nearestValidValue=function(t){var n,r,i,s;return i=this.getRange(),t=Math.min(i.max,t),t=Math.max(i.min,t),this.settings.allowedValues?(n=null,e.each(this.settings.allowedValues,function(){if(n===null||Math.abs(this-t)<Math.abs(n-t))return n=this}),n):this.settings.step?(r=(i.max-i.min)/this.settings.step,s=Math.floor((t-i.min)/this.settings.step),(t-i.min)%this.settings.step>this.settings.step/2&&s<r&&(s+=1),s*this.settings.step+i.min):t},t.prototype.valueToRatio=function(e){var t,n,r,i,s,o,u,a;if(this.settings.equalSteps){a=this.settings.allowedValues;for(i=o=0,u=a.length;o<u;i=++o){t=a[i];if(typeof n=="undefined"||n===null||Math.abs(t-e)<Math.abs(n-e))n=t,r=i}return this.settings.snapMid?(r+.5)/this.settings.allowedValues.length:r/(this.settings.allowedValues.length-1)}return s=this.getRange(),(e-s.min)/(s.max-s.min)},t.prototype.ratioToValue=function(e){var t,n,r,i,s;return this.settings.equalSteps?(s=this.settings.allowedValues.length,i=Math.round(e*s-.5),t=Math.min(i,this.settings.allowedValues.length-1),this.settings.allowedValues[t]):(n=this.getRange(),r=e*(n.max-n.min)+n.min,this.nearestValidValue(r))},t.prototype.valueChanged=function(t,n,r){var i;if(t.toString()===this.value.toString())return;return this.value=t,i={value:t,ratio:n,position:n*this.slider.outerWidth(),trigger:r,el:this.slider},this.input.val(t).trigger(e.Event("change",i)).trigger("slider:changed",i)},t}(),e.extend(e.fn,{simpleSlider:function(){var t,r,i;return i=arguments[0],t=2<=arguments.length?__slice.call(arguments,1):[],r=["setRatio","setValue"],e(this).each(function(){var s,o;return i&&__indexOf.call(r,i)>=0?(s=e(this).data("slider-object"),s[i].apply(s,t)):(o=i,e(this).data("slider-object",new n(e(this),o)))})}}),e(function(){return e("[data-slider]").each(function(){var t,n,r,i;return t=e(this),r={},n=t.data("slider-values"),n&&(r.allowedValues=function(){var e,t,r,s;r=n.split(","),s=[];for(e=0,t=r.length;e<t;e++)i=r[e],s.push(parseFloat(i));return s}()),t.data("slider-range")&&(r.range=t.data("slider-range").split(",")),t.data("slider-step")&&(r.step=t.data("slider-step")),r.snap=t.data("slider-snap"),r.equalSteps=t.data("slider-equal-steps"),t.data("slider-theme")&&(r.theme=t.data("slider-theme")),t.attr("data-slider-highlight")&&(r.highlight=t.data("slider-highlight")),t.data("slider-animate")!=null&&(r.animate=t.data("slider-animate")),t.simpleSlider(r)})})})(this.jQuery||this.Zepto,this);
\ No newline at end of file
{
"name" : "simple-slider",
"title" : "jQuery Simple Slider",
"description" : "Unobtrusive Numerical Slider",
"version" : "1.0.0",
"homepage" : "http://loopj.com/jquery-simple-slider",
"keywords" : [],
"author" : {
"name" : "James Smith",
"email" : "james@loopj.com",
"url" : "http://loopj.com"
},
"repository" : {
"type" : "git",
"url" : "https://github.com/loopj/jquery-simple-slider.git"
},
"bugs" : {
"url" : "https://github.com/loopj/jquery-simple-slider/issues"
},
"licenses": [{
"type": "MIT",
"url" : "http://mit-license.org/"
}],
"devDependencies" : {
"grunt" : "0.3.x",
"grunt-contrib": "0.2.x",
"grunt-growl": "git://github.com/loopj/grunt-growl.git#master"
},
"scripts": {
"test": "grunt"
}
}
\ No newline at end of file
......@@ -53,3 +53,50 @@
border-color: #496805;
}
.slider {
display: inline-block;
}
.slider .track {
height: 20px;
top: 50%;
}
.slider > .dragger, .slider > .dragger:hover {
border-radius: 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
width: 8px;
height: 24px;
margin-top: -12px!important;
text-shadow: 0 1px 0 #fff;
background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
background-repeat: repeat-x;
border-color: #2d6ca2;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
}
.slider > .dragger:hover {
background-color: #3071a9;
background-image: none;
border-color: #2d6ca2;
}
.slider > .highlight-track {
height: 20px;
top: 50%;
}
.slider + .output {
}
.slider > .track, .slider > .highlight-track {
border-radius: 5px;
}
/* review this later */
.slider {
width: 100%;
}
/*
jQuery Simple Slider
Copyright (c) 2012 James Smith (http://loopj.com)
Copyright (c) 2012, 2013 James Smith (http://loopj.com)
Copyright (c) 2013 Maarten van Grootel (http://maatenvangrootel.nl)
Copyright (c) 2013 Nathan Hunzaker (http://natehunzaker.com)
Copyright (c) 2013 Erik J. Nedwidek (http://github.com/nedwidek)
Licensed under the MIT license (http://mit-license.org/)
*/
......@@ -23,8 +26,12 @@ var __slice = [].slice,
classPrefix: null,
classSuffix: null,
theme: null,
highlight: false
highlight: false,
showScale: false
};
if(typeof options == 'undefined') {
options = this.loadDataOptions();
}
this.settings = $.extend({}, this.defaultOptions, options);
if (this.settings.theme) {
this.settings.classSuffix = "-" + this.settings.theme;
......@@ -106,6 +113,20 @@ var __slice = [].slice,
}
this.setSliderPositionFromValue(this.value);
ratio = this.valueToRatio(this.value);
if (this.settings.showScale) {
this.scale = this.createDivElement("scale");
this.minScale = this.createSpanElement("min-scale", this.scale);
this.maxScale = this.createSpanElement("max-scale", this.scale);
range = this.getRange();
this.minScale.html(range.min);
this.maxScale.html(range.max);
this.scale.css('marginTop', function(index, currentValue) {
return (parseInt(currentValue, 10) + this.previousSibling.offsetHeight / 2) + 'px';
});
}
this.input.trigger("slider:ready", {
value: this.value,
ratio: ratio,
......@@ -114,6 +135,44 @@ var __slice = [].slice,
});
}
SimpleSlider.prototype.loadDataOptions = function() {
var options = {};
allowedValues = this.input.data("slider-values");
if (allowedValues) {
options.allowedValues = (function() {
var _i, _len, _ref, _results;
_ref = allowedValues.split(",");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
_results.push(parseFloat(x));
}
return _results;
})();
}
if (this.input.data("slider-range")) {
options.range = this.input.data("slider-range").split(",");
}
if (this.input.data("slider-step")) {
options.step = this.input.data("slider-step");
}
options.snap = this.input.data("slider-snap");
options.equalSteps = this.input.data("slider-equal-steps");
if (this.input.data("slider-theme")) {
options.theme = this.input.data("slider-theme");
}
if (this.input.attr("data-slider-highlight")) {
options.highlight = this.input.data("slider-highlight");
}
if (this.input.data("slider-animate") != null) {
options.animate = this.input.data("slider-animate");
}
if (this.input.data("slider-showscale") != null) {
options.showScale = this.input.data("slider-showscale");
}
return options;
}
SimpleSlider.prototype.createDivElement = function(classname) {
var item;
item = $("<div>").addClass(classname).css({
......@@ -125,6 +184,12 @@ var __slice = [].slice,
return item;
};
SimpleSlider.prototype.createSpanElement = function(classname, parent) {
var item;
item = $("<span>").addClass(classname).appendTo(parent);
return item;
};
SimpleSlider.prototype.setRatio = function(ratio) {
var value;
ratio = Math.min(1, ratio);
......@@ -322,42 +387,14 @@ var __slice = [].slice,
});
}
});
/*
return $(function() {
return $("[data-slider]").each(function() {
var $el, allowedValues, settings, x;
$el = $(this);
settings = {};
allowedValues = $el.data("slider-values");
if (allowedValues) {
settings.allowedValues = (function() {
var _i, _len, _ref, _results;
_ref = allowedValues.split(",");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
_results.push(parseFloat(x));
}
return _results;
})();
}
if ($el.data("slider-range")) {
settings.range = $el.data("slider-range").split(",");
}
if ($el.data("slider-step")) {
settings.step = $el.data("slider-step");
}
settings.snap = $el.data("slider-snap");
settings.equalSteps = $el.data("slider-equal-steps");
if ($el.data("slider-theme")) {
settings.theme = $el.data("slider-theme");
}
if ($el.attr("data-slider-highlight")) {
settings.highlight = $el.data("slider-highlight");
}
if ($el.data("slider-animate") != null) {
settings.animate = $el.data("slider-animate");
}
return $el.simpleSlider(settings);
return $el.simpleSlider();
});
});
*/
})(this.jQuery || this.Zepto, this);
/*
* jQuery Simple Slider: Unobtrusive Numerical Slider
* Version 1.0.0
*
* Copyright (c) 2013 James Smith (http://loopj.com)
*
* Licensed under the MIT license (http://mit-license.org/)
*
*/
var __slice=[].slice,__indexOf=[].indexOf||function(c){for(var b=0,a=this.length;b<a;b++){if(b in this&&this[b]===c){return b}}return -1};(function(c,a){var b;b=(function(){function d(e,f){var g,h=this;this.input=e;this.defaultOptions={animate:true,snapMid:false,classPrefix:null,classSuffix:null,theme:null,highlight:false,showScale:false};if(typeof f=="undefined"){f=this.loadDataOptions()}this.settings=c.extend({},this.defaultOptions,f);if(this.settings.theme){this.settings.classSuffix="-"+this.settings.theme}this.input.hide();this.slider=c("<div>").addClass("slider"+(this.settings.classSuffix||"")).css({position:"relative",userSelect:"none",boxSizing:"border-box"}).insertBefore(this.input);if(this.input.attr("id")){this.slider.attr("id",this.input.attr("id")+"-slider")}this.track=this.createDivElement("track").css({width:"100%"});if(this.settings.highlight){this.highlightTrack=this.createDivElement("highlight-track").css({width:"0"})}this.dragger=this.createDivElement("dragger");this.slider.css({minHeight:this.dragger.outerHeight(),marginLeft:this.dragger.outerWidth()/2,marginRight:this.dragger.outerWidth()/2});this.track.css({marginTop:this.track.outerHeight()/-2});if(this.settings.highlight){this.highlightTrack.css({marginTop:this.track.outerHeight()/-2})}this.dragger.css({marginTop:this.dragger.outerWidth()/-2,marginLeft:this.dragger.outerWidth()/-2});this.track.mousedown(function(i){return h.trackEvent(i)});if(this.settings.highlight){this.highlightTrack.mousedown(function(i){return h.trackEvent(i)})}this.dragger.mousedown(function(i){if(i.which!==1){return}h.dragging=true;h.dragger.addClass("dragging");h.domDrag(i.pageX,i.pageY);return false});c("body").mousemove(function(i){if(h.dragging){h.domDrag(i.pageX,i.pageY);return c("body").css({cursor:"pointer"})}}).mouseup(function(i){if(h.dragging){h.dragging=false;h.dragger.removeClass("dragging");return c("body").css({cursor:"auto"})}});this.pagePos=0;if(this.input.val()===""){this.value=this.getRange().min;this.input.val(this.value)}else{this.value=this.nearestValidValue(this.input.val())}this.setSliderPositionFromValue(this.value);g=this.valueToRatio(this.value);if(this.settings.showScale){this.scale=this.createDivElement("scale");this.minScale=this.createSpanElement("min-scale",this.scale);this.maxScale=this.createSpanElement("max-scale",this.scale);range=this.getRange();this.minScale.html(range.min);this.maxScale.html(range.max);this.scale.css("marginTop",function(i,j){return(parseInt(j,10)+this.previousSibling.offsetHeight/2)+"px"})}this.input.trigger("slider:ready",{value:this.value,ratio:g,position:g*this.slider.outerWidth(),el:this.slider})}d.prototype.loadDataOptions=function(){var e={};allowedValues=this.input.data("slider-values");if(allowedValues){e.allowedValues=(function(){var i,g,h,f;h=allowedValues.split(",");f=[];for(i=0,g=h.length;i<g;i++){x=h[i];f.push(parseFloat(x))}return f})()}if(this.input.data("slider-range")){e.range=this.input.data("slider-range").split(",")}if(this.input.data("slider-step")){e.step=this.input.data("slider-step")}e.snap=this.input.data("slider-snap");e.equalSteps=this.input.data("slider-equal-steps");if(this.input.data("slider-theme")){e.theme=this.input.data("slider-theme")}if(this.input.attr("data-slider-highlight")){e.highlight=this.input.data("slider-highlight")}if(this.input.data("slider-animate")!=null){e.animate=this.input.data("slider-animate")}if(this.input.data("slider-showscale")!=null){e.showScale=this.input.data("slider-showscale")}return e};d.prototype.createDivElement=function(f){var e;e=c("<div>").addClass(f).css({position:"absolute",top:"50%",userSelect:"none",cursor:"pointer"}).appendTo(this.slider);return e};d.prototype.createSpanElement=function(g,e){var f;f=c("<span>").addClass(g).appendTo(e);return f};d.prototype.setRatio=function(e){var f;e=Math.min(1,e);e=Math.max(0,e);f=this.ratioToValue(e);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setRatio")};d.prototype.setValue=function(f){var e;f=this.nearestValidValue(f);e=this.valueToRatio(f);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setValue")};d.prototype.trackEvent=function(f){if(f.which!==1){return}this.domDrag(f.pageX,f.pageY,true);this.dragging=true;return false};d.prototype.domDrag=function(i,g,e){var f,h,j;if(e==null){e=false}f=i-this.slider.offset().left;f=Math.min(this.slider.outerWidth(),f);f=Math.max(0,f);if(this.pagePos!==f){this.pagePos=f;h=f/this.slider.outerWidth();j=this.ratioToValue(h);this.valueChanged(j,h,"domDrag");if(this.settings.snap){return this.setSliderPositionFromValue(j,e)}else{return this.setSliderPosition(f,e)}}};d.prototype.setSliderPosition=function(e,f){if(f==null){f=false}if(f&&this.settings.animate){this.dragger.animate({left:e},200);if(this.settings.highlight){return this.highlightTrack.animate({width:e},200)}}else{this.dragger.css({left:e});if(this.settings.highlight){return this.highlightTrack.css({width:e})}}};d.prototype.setSliderPositionFromValue=function(g,e){var f;if(e==null){e=false}f=this.valueToRatio(g);return this.setSliderPosition(f*this.slider.outerWidth(),e)};d.prototype.getRange=function(){if(this.settings.allowedValues){return{min:Math.min.apply(Math,this.settings.allowedValues),max:Math.max.apply(Math,this.settings.allowedValues)}}else{if(this.settings.range){return{min:parseFloat(this.settings.range[0]),max:parseFloat(this.settings.range[1])}}else{return{min:0,max:1}}}};d.prototype.nearestValidValue=function(i){var h,g,f,e;f=this.getRange();i=Math.min(f.max,i);i=Math.max(f.min,i);if(this.settings.allowedValues){h=null;c.each(this.settings.allowedValues,function(){if(h===null||Math.abs(this-i)<Math.abs(h-i)){return h=this}});return h}else{if(this.settings.step){g=(f.max-f.min)/this.settings.step;e=Math.floor((i-f.min)/this.settings.step);if((i-f.min)%this.settings.step>this.settings.step/2&&e<g){e+=1}return e*this.settings.step+f.min}else{return i}}};d.prototype.valueToRatio=function(l){var f,e,j,m,i,g,k,h;if(this.settings.equalSteps){h=this.settings.allowedValues;for(m=g=0,k=h.length;g<k;m=++g){f=h[m];if(!(typeof e!=="undefined"&&e!==null)||Math.abs(f-l)<Math.abs(e-l)){e=f;j=m}}if(this.settings.snapMid){return(j+0.5)/this.settings.allowedValues.length}else{return j/(this.settings.allowedValues.length-1)}}else{i=this.getRange();return(l-i.min)/(i.max-i.min)}};d.prototype.ratioToValue=function(h){var e,g,j,i,f;if(this.settings.equalSteps){f=this.settings.allowedValues.length;i=Math.round(h*f-0.5);e=Math.min(i,this.settings.allowedValues.length-1);return this.settings.allowedValues[e]}else{g=this.getRange();j=h*(g.max-g.min)+g.min;return this.nearestValidValue(j)}};d.prototype.valueChanged=function(h,f,e){var g;if(h.toString()===this.value.toString()){return}this.value=h;g={value:h,ratio:f,position:f*this.slider.outerWidth(),trigger:e,el:this.slider};return this.input.val(h).trigger(c.Event("change",g)).trigger("slider:changed",g)};return d})();c.extend(c.fn,{simpleSlider:function(){var e,d,f;f=arguments[0],e=2<=arguments.length?__slice.call(arguments,1):[];d=["setRatio","setValue"];return c(this).each(function(){var h,g;if(f&&__indexOf.call(d,f)>=0){h=c(this).data("slider-object");return h[f].apply(h,e)}else{g=f;return c(this).data("slider-object",new b(c(this),g))}})}});return c(function(){return c("[data-slider]").each(function(){var e,g,f,d;e=c(this);return e.simpleSlider()})})})(this.jQuery||this.Zepto,this);
......@@ -2,13 +2,17 @@ var vlans = [];
var disks = [];
$(function() {
vmCustomizeLoaded();
if($(".vm-create-template-list").length) {
vmCreateLoaded();
} else {
vmCustomizeLoaded();
}
});
function vmCreateLoaded() {
$(".vm-create-template-details").hide();
$(".vm-create-template-summary").click(function() {
$(".vm-create-template-summary").unbind("click").click(function() {
$(this).next(".vm-create-template-details").slideToggle();
});
......@@ -64,9 +68,18 @@ function vmCreateLoaded() {
return false;
});
$('.progress-bar').each(function() {
var min = $(this).attr('aria-valuemin');
var max = $(this).attr('aria-valuemax');
var now = $(this).attr('aria-valuenow');
var siz = (now-min)*100/(max-min);
$(this).css('width', siz+'%');
});
}
function vmCustomizeLoaded() {
$("[title]").tooltip();
/* network thingies */
/* add network */
......@@ -92,7 +105,7 @@ function vmCustomizeLoaded() {
/* add dummy text if no more networks are available */
if($('#vm-create-network-add-select option').length < 1) {
$('#vm-create-network-add-button').attr('disabled', true);
$('#vm-create-network-add-select').html('<option value="-1">No more networks!</option>');
$('#vm-create-network-add-select').html('<option value="-1">' + gettext("No more networks.") + '</option>');
}
return false;
......@@ -124,7 +137,7 @@ function vmCustomizeLoaded() {
/* remove the selection from the multiple select */
$('#vm-create-network-add-vlan option[value="' + vlan_pk + '"]').prop('selected', false);
if ($('#vm-create-network-list').children('span').length < 1) {
$('#vm-create-network-list').append('Not added to any network!');
$('#vm-create-network-list').append(gettext("Not added to any network"));
}
});
return false;
......@@ -155,7 +168,7 @@ function vmCustomizeLoaded() {
// if all networks are added add a dummy and disable the add button
if($("#vm-create-network-add-select option").length < 1) {
$("#vm-create-network-add-select").html('<option value="-1">No more networks!</option>');
$("#vm-create-network-add-select").html('<option value="-1">' + gettext("No more networks.") + '</option>');
$('#vm-create-network-add-button').attr('disabled', true);
}
......@@ -170,54 +183,6 @@ function vmCustomizeLoaded() {
/* ----- end of networks thingies ----- */
/* add disk */
$('#vm-create-disk-add-button').click(function() {
var disk_pk = $('#vm-create-disk-add-select :selected').val();
var name = $('#vm-create-disk-add-select :selected').text();
if ($('#vm-create-disk-list').children('span').length < 1) {
$('#vm-create-disk-list').html('');
}
$('#vm-create-disk-list').append(
vmCreateDiskLabel(disk_pk, name)
);
/* select the disk from the multiple select */
$('#vm-create-disk-add-form option[value="' + disk_pk + '"]').prop('selected', true);
$('option:selected', $('#vm-create-disk-add-select')).remove();
/* add dummy text if no more disks are available */
if($('#vm-create-disk-add-select option').length < 1) {
$('#vm-create-disk-add-button').attr('disabled', true);
$('#vm-create-disk-add-select').html('<option value="-1">We are out of &lt;options&gt; hehe</option>');
}
return false;
});
/* remove disk */
// event for disk remove button (icon, X)
$('body').on('click', '.vm-create-remove-disk', function() {
var disk_pk = ($(this).parent('span').prop('id')).replace('disk-', '')
$(this).parent('span').fadeOut(500, function() {
/* remove the disk label */
$(this).remove();
var disk_name = $(this).text();
/* remove the selection from the multiple select */
$('#vm-create-disk-add-form option[value="' + disk_pk + '"]').prop('selected', false);
if ($('#vm-create-disk-list').children('span').length < 1) {
$('#vm-create-disk-list').append('No disks are added!');
}
});
return false;
});
/* copy disks from hidden select */
$('#vm-create-disk-add-form option').each(function() {
var text = $(this).text();
......@@ -244,6 +209,14 @@ function vmCustomizeLoaded() {
/* start vm button clicks */
$('#vm-create-customized-start').click(function() {
var error = false;
$(".cpu-count-input, .ram-input, #id_name, #id_amount ").each(function() {
if(!$(this)[0].checkValidity()) {
error = true;
}
});
if(error) return true;
$.ajax({
url: '/dashboard/vm/create/',
headers: {"X-CSRFToken": getCookie('csrftoken')},
......@@ -284,6 +257,7 @@ function vmCustomizeLoaded() {
/* for no js stuff */
$('.no-js-hidden').show();
$('.js-hidden').hide();
}
......@@ -294,5 +268,5 @@ function vmCreateNetworkLabel(pk, name, managed) {
function vmCreateDiskLabel(pk, name) {
var style = "float: left; margin: 5px 5px 5px 0;";
return '<span id="disk-' + pk + '" class="label label-primary" style="' + style + '"><i class="fa fa-file"></i> ' + name + ' <a href="#" class="hover-black vm-create-remove-disk"><i class="fa fa-times-circle"></i></a></span> ';
return '<span id="disk-' + pk + '" class="label label-primary" style="' + style + '"><i class="fa fa-file"></i> ' + name + '</span> ';
}
......@@ -27,6 +27,15 @@ $(function() {
/* save resources */
$('#vm-details-resources-save').click(function() {
var error = false;
$(".cpu-count-input, .ram-input").each(function() {
if(!$(this)[0].checkValidity()) {
error = true;
}
});
if(error) return true;
$('i.fa-floppy-o', this).removeClass("fa-floppy-o").addClass("fa-refresh fa-spin");
var vm = $(this).data("vm");
$.ajax({
......@@ -34,8 +43,12 @@ $(function() {
url: "/dashboard/vm/" + vm + "/op/resources_change/",
data: $('#vm-details-resources-form').serialize(),
success: function(data, textStatus, xhr) {
if(data.success) {
$('a[href="#activity"]').trigger("click");
} else {
addMessage(data.messages.join("<br />"), "danger");
}
$("#vm-details-resources-save i").removeClass('fa-refresh fa-spin').addClass("fa-floppy-o");
$('a[href="#activity"]').trigger("click");
},
error: function(xhr, textStatus, error) {
$("#vm-details-resources-save i").removeClass('fa-refresh fa-spin').addClass("fa-floppy-o");
......@@ -385,12 +398,12 @@ function checkNewActivity(runs) {
$("[data-target=#_console]").attr("data-toggle", "_pill").attr("href", "#").parent("li").addClass("disabled");
}
if(data['status'] == "STOPPED") {
$(".enabled-when-stopped").prop("disabled", false);
$(".hide-when-stopped").hide();
if(data['status'] == "STOPPED" || data['status'] == "PENDING") {
$(".change-resources-button").prop("disabled", false);
$(".change-resources-help").hide();
} else {
$(".enabled-when-stopped").prop("disabled", true);
$(".hide-when-stopped").show();
$(".change-resources-button").prop("disabled", true);
$(".change-resources-help").show();
}
if(runs > 0 && decideActivityRefresh()) {
......
......@@ -68,6 +68,7 @@
</body>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="{{ STATIC_URL }}dashboard/loopj-jquery-simple-slider/js/simple-slider.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="{{ STATIC_URL }}jsi18n/{{ LANGUAGE_CODE }}/djangojs.js"></script>
{% include 'autocomplete_light/static.html' %}
......
{% load i18n %}
{% load sizefieldtags %}
{% load crispy_forms_tags %}
<div class="row">
<div class="col-sm-3" style="font-weight: bold;">
<i class="fa fa-trophy"></i> {% trans "CPU priority" %}
</div>
<div class="col-sm-6">
<input type="text" class="vm-slider cpu-priority-slider"
disabled placeholder="{% trans "Enable JS for fancy sliders" %}"
data-slider="true" data-slider-highlight="true" data-slider-range="10, 100"
data-slider-values="0, 10, 30, 80, 100" data-slider-snap="true"/>
</div>
<div class="col-sm-3">
<div class="input-group">
{{ field_priority }}
<span class="input-group-addon input-tags">
<i class="fa fa-question" title="{% trans "The priority of the CPU" %}"></i>
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-3" style="font-weight: bold;">
<i class="fa fa-cogs"></i> {% trans "CPU count" %}
</div>
<div class="col-sm-6">
<input type="text" class="vm-slider cpu-count-slider"
disabled placeholder="{% trans "Enable JS for fancy sliders" %}"
data-slider="true" data-slider-highlight="true" data-slider-range="0, 10"
data-slider-step="true" data-slider-snap="true"/>
</div>
<div class="col-sm-3">
<div class="input-group">
{{ field_num_cores }}
<span class="input-group-addon input-tags">
<i class="fa fa-question" title="{% trans "Number of CPU cores" %}"></i>
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-3" style="font-weight: bold;">
<i class="fa fa-ticket"></i> {% trans "RAM amount" %}
</div>
<div class="col-sm-6">
<input type="text" class="vm-slider ram-slider"
disabled placeholder="{% trans "Enable JS for fancy sliders" %}"
data-slider="true" data-slider-highlight="true" data-slider-range="0, 8192"
data-slider-step="128" data-slider-snap="true"/>
</div>
<div class="col-sm-3">
<div class="input-group">
{{ field_ram_size }}
<span class="input-group-addon input-tags">
MiB
</span>
<span class="input-group-addon input-tags">
<i title="{% trans "RAM size in mebibytes" %}" class="fa fa-question"></i>
</span>
</div>
</div>
</div>
{% load i18n %}
{% load crispy_forms_tags %}
{% if leases < 1 %}
<form action="" method="POST">
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% csrf_token %}
{{ form.name|as_crispy_field }}
<fieldset class="resources-sliders">
<legend>{% trans "Resource configuration" %}</legend>
{% include "dashboard/_resources-sliders.html" with field_priority=form.priority field_num_cores=form.num_cores field_ram_size=form.ram_size %}
{{ form.max_ram_size|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "Virtual machine settings" %}</legend>
{{ form.arch|as_crispy_field }}
{{ form.access_method|as_crispy_field }}
{{ form.boot_menu|as_crispy_field }}
{{ form.raw_data|as_crispy_field }}
{{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "External resources" %}</legend>
{{ form.networks|as_crispy_field }}
{{ form.lease|as_crispy_field }}
{% if show_lease_create %}
<div class="alert alert-warning">
{% trans "You haven't created any leases yet, but you need one to create a template!" %}
{% trans "You haven't created any leases yet, but you need one to create a template." %}
<a href="{% url "dashboard.views.lease-create" %}">{% trans "Create a new lease now." %}</a>
</div>
{% endif %}
{{ form.tags|as_crispy_field }}
</fieldset>
<input type="submit" value="{% trans "Create new template" %}" class="btn btn-success">
</form>
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% crispy form %}
<style>
fieldset {
......@@ -21,8 +53,3 @@
font-weight: bold;
}
</style>
<script>
$(function() {
$("#hint_id_num_cores, #hint_id_priority, #hint_id_ram_size").hide();
});
</script>
......@@ -76,48 +76,6 @@
</div>
<style>
.row {
margin-bottom: 15px;
}
.vm-create-template {
max-width: 800px;
border: 1px solid black;
border-bottom: none;
}
.vm-create-template-list .vm-create-template:last-child {
border-bottom: 1px solid black;
}
.vm-create-template-summary {
padding: 15px;
cursor: pointer;
}
.vm-create-template:nth-child(odd) .vm-create-template-summary {
background: #F5F5F5;
}
.vm-create-template-list .vm-create-template-summary:hover {
background: #D2D2D2;
}
.vm-create-template-details {
border-top: 1px dashed #D3D3D3;
padding: 15px;
}
.vm-create-template-details ul {
list-style: none;
padding: 0 15px;
}
.vm-create-template-details li {
border-bottom: 1px dotted #aaa;
padding: 5px 0px;
}
.progress {
position: relative;
width: 200px;
......@@ -139,15 +97,3 @@
font-size: 10px;
}
</style>
{% block "extra-js" %}
<script>
$('.progress-bar').each(function() {
var min = $(this).attr('aria-valuemin');
var max = $(this).attr('aria-valuemax');
var now = $(this).attr('aria-valuenow');
var siz = (now-min)*100/(max-min);
$(this).css('width', siz+'%');
});
</script>
{% endblock %}
{% load crispy_forms_tags %}
{% load i18n %}
{% load sizefieldtags %}
{% crispy vm_create_form %}
{% include "display-form-errors.html" with form=vm_create_form %}
<form method="POST">
{% csrf_token %}
<script src="/static/dashboard/vm-create.js"></script>
{{ vm_create_form.template }}
{{ vm_create_form.customized }}
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<button id="vm-create-customized-start" class="btn btn-success"
style="float: right; margin-top: 24px;">
<i class="fa fa-play"></i>
{% trans "Start" %}
</button>
<label>{% trans "Name" %}*</label>
{{ vm_create_form.name }}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-10">
<div class="form-group">
<label>{% trans "Amount" %}*</label>
{{ vm_create_form.amount }}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h2>{% trans "Resources" %}</h2>
</div>
</div>
<!-- resources -->
<div class="resources-sliders" style="max-width: 720px;">
{% include "dashboard/_resources-sliders.html" with field_priority=vm_create_form.cpu_priority field_num_cores=vm_create_form.cpu_count field_ram_size=vm_create_form.ram_size %}
</div>
<div class="row">
<div class="col-sm-4">
<h2>{% trans "Disks" %}</h2>
</div>
<div class="col-sm-8">
<div class="js-hidden">
{{ vm_create_form.disks }}
</div>
<div class="no-js-hidden">
<h3 id="vm-create-disk-list">{% trans "No disks are added." %}</h3>
<div style="clear: both;"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<h2>{% trans "Network" %}</h2>
</div>
<div class="col-sm-8" style="padding-top: 3px;">
<div class="js-hidden" style="padding-top: 15px; max-width: 450px;">
{{ vm_create_form.networks }}
</div>
<div class="no-js-hidden">
<h3 id="vm-create-network-list">
{% trans "Not added to any network." %}
</h3>
<h3 id="vm-create-network-add">
<div class="input-group" style="max-width: 330px;">
<select class="form-control font-awesome-font" id="vm-create-network-add-select">
</select>
<div class="input-group-btn">
<a id="vm-create-network-add-button" class="btn btn-success">
<i class="fa fa-plus-circle"></i>
</a>
</div><!-- .input-group-btn -->
</div><!-- .input-group -->
</h3><!-- #vm-create-network-add -->
</div><!-- .no-js-hidden -->
</div><!-- .col-sm-8 -->
</div><!-- .row -->
</form>
<script>
try {
vmCustomizeLoaded();
} catch(e) {}
</script>
......@@ -5,7 +5,7 @@
{% block extra_link %}
<link rel="stylesheet" href="{{ STATIC_URL }}dashboard/bootstrap-slider/slider.css"/>
<link rel="stylesheet" href="{{ STATIC_URL }}dashboard/loopj-jquery-simple-slider/css/simple-slider.css"/>
<link href="{{ STATIC_URL }}dashboard/bootstrap-tour.min.css" rel="stylesheet">
<link href="{{ STATIC_URL }}dashboard/dashboard.css" rel="stylesheet">
{% endblock %}
......@@ -55,6 +55,5 @@
{% block extra_script %}
<script src="{{ STATIC_URL }}dashboard/js/jquery.knob.js"></script>
<script src="{{ STATIC_URL}}dashboard/bootstrap-slider/bootstrap-slider.js"></script>
<script src="{{ STATIC_URL }}dashboard/dashboard.js"></script>
{% endblock %}
{% load crispy_forms_tags %}
<style>
.row {
margin-bottom: 15px;
}
</style>
<form method="POST" action="{% url "dashboard.views.group-create" %}">
{% csrf_token %}
......
{% load crispy_forms_tags %}
<form method="POST" action="/dashboard/node/create/" id="node-create-form">
{% csrf_token %}
{% crispy formset formset.form.helper %}
</form>
<style>
.row {
margin-bottom: 15px;
#node-create-form .row {
margin-bottom: 10px;
}
</style>
<form method="POST" action="/dashboard/node/create/">
{% csrf_token %}
{% crispy formset formset.form.helper %}
</form>
......@@ -16,7 +16,7 @@
{% endblock %}
{% block extra_js %}
{% if template == "dashboard/_vm-create-1.html" %}
{% if template == "dashboard/_vm-create-1.html" or template == "dashboard/_vm-create-2.html" %}
<script src="{{ STATIC_URL }}dashboard/vm-create.js"></script>
{% endif %}
{% endblock %}
......@@ -15,10 +15,41 @@
<h3 class="no-margin"><i class="fa fa-puzzle-piece"></i> {% trans "Edit template" %}</h3>
</div>
<div class="panel-body">
<form action="" method="POST">
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% crispy form %}
{% csrf_token %}
{{ form.name|as_crispy_field }}
<fieldset class="resources-sliders">
<legend>{% trans "Resource configuration" %}</legend>
{% include "dashboard/_resources-sliders.html" with field_priority=form.priority field_num_cores=form.num_cores field_ram_size=form.ram_size %}
{{ form.max_ram_size|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "Virtual machine settings" %}</legend>
{{ form.arch|as_crispy_field }}
{{ form.access_method|as_crispy_field }}
{{ form.boot_menu|as_crispy_field }}
{{ form.raw_data|as_crispy_field }}
{{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "External resources" %}</legend>
{{ form.networks|as_crispy_field }}
{{ form.lease|as_crispy_field }}
{{ form.tags|as_crispy_field }}
</fieldset>
<input type="submit" value="{% trans "Save changes" %}" class="btn btn-primary">
</form>
</div>
</div>
</div>
......
......@@ -75,6 +75,8 @@
<dd>
{% if instance.get_connect_port %}
{{ instance.get_connect_host }}:<strong>{{ instance.get_connect_port }}</strong>
{% elif instance.interface_set.count < 1%}
<strong>{% trans "The VM doesn't have any network interface." %}</strong>
{% else %}
<strong>{% trans "The required port for this protocol is not forwarded." %}</strong>
{% endif %}
......@@ -109,8 +111,7 @@
<div class="input-group" id="dashboard-vm-details-connect-command">
<span class="input-group-addon input-tags">{% trans "Command" %}</span>
<input type="text" spellcheck="false"
value="{% if instance.get_connect_command %}{{ instance.get_connect_command }}{% else %}
{% trans "Connection is not possible." %}{% endif %}"
value="{% if instance.get_connect_command %}{{ instance.get_connect_command }}{% else %}{% trans "Connection is not possible." %}{% endif %}"
id="vm-details-connection-string" class="form-control input-tags" />
<span class="input-group-addon input-tags" id="vm-details-connection-string-copy">
<i class="fa fa-copy" title="{% trans "Select all" %}"></i>
......
......@@ -2,55 +2,26 @@
{% load sizefieldtags %}
{% load crispy_forms_tags %}
<form id="vm-details-resources-form" method="POST" action="">
<form method="POST" action="{{ op.resources_change.get_url }}" id="vm-details-resources-form">
{% csrf_token %}
<p class="row">
<div class="col-sm-3">
<label for="vm-cpu-priority-slider"><i class="fa fa-trophy"></i> {% trans "CPU priority" %}</label>
</div>
<div class="col-sm-9">
<input name="cpu-priority" type="text" id="vm-cpu-priority-slider" class="vm-slider" value="{{ instance.priority }}" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="{{ instance.priority }}" data-slider-orientation="horizontal" data-slider-handle="square" data-slider-tooltip="hide"/>
</div>
</p>
<p class="row">
<div class="col-sm-3">
<label for="cpu-count-slider"><i class="fa fa-cogs"></i> {% trans "CPU count" %}</label>
</div>
<div class="col-sm-9">
<input name="cpu-count" type="text" id="vm-cpu-count-slider" class="vm-slider" value=" {{ instance.num_cores }}" data-slider-min="0" data-slider-max="8" data-slider-step="1" data-slider-value="{{ instance.num_cores }}" data-slider-orientation="horizontal" data-slider-handle="square" data-slider-tooltip="hide"/>
</div>
</p>
<p class="row">
<div class="col-sm-3">
<label for="ram-slider"><i class="fa fa-ticket"></i> {% trans "RAM amount" %}</label>
</div>
<div class="col-sm-9">
<input name="ram-size" type="text" id="vm-ram-size-slider" class="vm-slider" value="{{ instance.ram_size }}" data-slider-min="128" data-slider-max="4096" data-slider-step="128" data-slider-value="{{ instance.ram_size }}" data-slider-orientation="horizontal" data-slider-handle="square" data-slider-tooltip="hide"/> MiB
</div>
</p>
{% include "dashboard/_resources-sliders.html" with field_priority=resources_form.priority field_num_cores=resources_form.num_cores field_ram_size=resources_form.ram_size %}
{% if can_change_resources %}
<p class="row">
<div class="col-sm-12">
<button type="submit" class="btn btn-success btn-sm enabled-when-stopped" id="vm-details-resources-save"
data-vm="{{ instance.pk }}"
{% if not op.resources_change %}disabled{% endif %}>
<button type="submit" class="btn btn-success btn-sm change-resources-button"
id="vm-details-resources-save" data-vm="{{ instance.pk }}"
{% if op.resources_change.disabled %}disabled{% endif %}>
<i class="fa fa-floppy-o"></i> {% trans "Save resources" %}
</button>
<span class="hide-when-stopped"
{% if op.resources_change %}style="display: none;"{% endif %}
<span class="change-resources-help"
{% if not op.resources_change.disabled %}style="display: none;"{% endif %}
>{% trans "Stop your VM to change resources." %}</span>
</div>
</p>
{% endif %}
</form>
<hr />
<div class="row" id="vm-details-resources-disk">
<div class="col-sm-11">
<h3>
......
......@@ -282,10 +282,12 @@ class VmDetailTest(LoginMixin, TestCase):
c = Client()
self.login(c, 'superuser')
kwargs = InstanceTemplate.objects.get(id=1).__dict__.copy()
kwargs.update(name='t2', lease=1, disks=1, raw_data='tst2')
kwargs.update(name='t2', lease=1, disks=1,
raw_data='<devices></devices>')
response = c.post('/dashboard/template/1/', kwargs)
self.assertEqual(response.status_code, 302)
self.assertEqual(InstanceTemplate.objects.get(id=1).raw_data, 'tst2')
self.assertEqual(InstanceTemplate.objects.get(id=1).raw_data,
"<devices></devices>")
def test_permitted_lease_delete_w_template_using_it(self):
c = Client()
......@@ -565,7 +567,7 @@ class VmDetailTest(LoginMixin, TestCase):
'amount': 2,
'customized': 1,
'template': 1,
'cpu_priority': 1, 'cpu_count': 1, 'ram_size': 1,
'cpu_priority': 10, 'cpu_count': 1, 'ram_size': 128,
'network': [],
})
......
......@@ -70,7 +70,7 @@ from .forms import (
VmSaveForm, UserKeyForm, VmRenewForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm,
VmAddInterfaceForm,
VmResourcesForm, VmAddInterfaceForm,
)
from .tables import (
......@@ -327,6 +327,8 @@ class VmDetailView(CheckedDetailView):
context['ipv6_port'] = instance.get_connect_port(use_ipv6=True)
# resources forms
context['resources_form'] = VmResourcesForm(instance=instance)
if self.request.user.is_superuser:
context['traits_form'] = TraitsForm(instance=instance)
context['raw_data_form'] = RawDataForm(instance=instance)
......@@ -351,8 +353,6 @@ class VmDetailView(CheckedDetailView):
return v(request)
raise Http404()
raise Http404()
def __set_name(self, request):
self.object = self.get_object()
if not self.object.has_level(request.user, 'owner'):
......@@ -788,22 +788,35 @@ class VmResourcesChangeView(VmOperationView):
op = 'resources_change'
icon = "save"
show_in_toolbar = False
wait_for_result = 0.5
def post(self, request, extra=None, *args, **kwargs):
if extra is None:
extra = {}
resources = {
'num_cores': "cpu-count",
'priority': "cpu-priority",
'ram_size': "ram-size",
"max_ram_size": "ram-size", # TODO
}
for k, v in resources.iteritems():
extra[k] = request.POST.get(v)
instance = get_object_or_404(Instance, pk=kwargs['pk'])
return super(VmResourcesChangeView, self).post(request, extra,
*args, **kwargs)
form = VmResourcesForm(request.POST, instance=instance)
if not form.is_valid():
for f in form.errors:
messages.error(request, "<strong>%s</strong>: %s" % (
f, form.errors[f].as_text()
))
if request.is_ajax(): # this is not too nice
store = messages.get_messages(request)
store.used = True
return HttpResponse(
json.dumps({'success': False,
'messages': [unicode(m) for m in store]}),
content_type="application=json"
)
else:
return redirect(instance.get_absolute_url() + "#resources")
else:
extra = form.cleaned_data
extra['max_ram_size'] = extra['ram_size']
return super(VmResourcesChangeView, self).post(request, extra,
*args, **kwargs)
class TokenOperationView(OperationView):
......@@ -1358,10 +1371,13 @@ class TemplateCreate(SuccessMessageMixin, CreateView):
def get_context_data(self, *args, **kwargs):
context = super(TemplateCreate, self).get_context_data(*args, **kwargs)
num_leases = Lease.get_objects_with_level("user",
self.request.user).count()
can_create_leases = self.request.user.has_perm("create_leases")
context.update({
'box_title': _("Create a new base VM"),
'template': "dashboard/_template-create.html",
'leases': Lease.objects.count()
'show_lease_create': num_leases < 1 and can_create_leases
})
return context
......
......@@ -18,6 +18,7 @@
from __future__ import absolute_import, unicode_literals
from datetime import timedelta, datetime
from django.core.validators import MinValueValidator
from django.db.models import Model, CharField, IntegerField, permalink
from django.utils.translation import ugettext_lazy as _
from django.utils.timesince import timeuntil
......@@ -37,16 +38,20 @@ class BaseResourceConfigModel(Model):
"""
num_cores = IntegerField(verbose_name=_('number of cores'),
help_text=_('Number of virtual CPU cores '
'available to the virtual machine.'))
'available to the virtual machine.'),
validators=[MinValueValidator(0)])
ram_size = IntegerField(verbose_name=_('RAM size'),
help_text=_('Mebibytes of memory.'))
help_text=_('Mebibytes of memory.'),
validators=[MinValueValidator(0)])
max_ram_size = IntegerField(verbose_name=_('maximal RAM size'),
help_text=_('Upper memory size limit '
'for balloning.'))
'for balloning.'),
validators=[MinValueValidator(0)])
arch = CharField(max_length=10, verbose_name=_('architecture'),
choices=ARCHITECTURES)
priority = IntegerField(verbose_name=_('priority'),
help_text=_('CPU priority.'))
help_text=_('CPU priority.'),
validators=[MinValueValidator(0)])
class Meta:
abstract = True
......
......@@ -957,7 +957,7 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
for a in acts:
if (latest == a.activity_code and
merged_acts[-1].result == a.result and
merged_acts[-1].result_data == a.result_data and
a.finished and merged_acts[-1].finished and
a.user == merged_acts[-1].user and
(merged_acts[-1].finished - a.finished).days < 7 and
......
......@@ -857,7 +857,8 @@ class ResourcesOperation(InstanceOperation):
required_perms = ('vm.change_resources', )
accept_states = ('STOPPED', 'PENDING', )
def _operation(self, user, num_cores, ram_size, max_ram_size, priority):
def _operation(self, user, activity,
num_cores, ram_size, max_ram_size, priority):
self.instance.num_cores = num_cores
self.instance.ram_size = ram_size
......@@ -867,6 +868,12 @@ class ResourcesOperation(InstanceOperation):
self.instance.full_clean()
self.instance.save()
activity.result = create_readable(ugettext_noop(
"Priority: %(priority)s, Num cores: %(num_cores)s, "
"Ram size: %(ram_size)s"), priority=priority, num_cores=num_cores,
ram_size=ram_size
)
register_operation(ResourcesOperation)
......
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