Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ f87e79a4

History | View | Annotate | Download (20.4 kB)

1
{% load i18n %}
2

    
3
<div id="machines" class="separator"></div>
4

    
5
<!-- the create button -->
6
<div id="createcontainer">
7
    <span id="createbody">{% trans "Start by creating a new Virtual Machine:" %}</span><br />
8
    <a id="create" rel="#wizard" href="#">{% trans "Create New +" %}</a>
9
</div>
10

    
11
<!-- changing between standard/list view -->
12
<div id="view-select">
13
    <a id="standard" href="/machines/standard">#</a>
14
    <span class="view-separator">|</span>
15
    <a id="list" href="/machines/list">=</a>
16
</div>
17

    
18
<div id="emptymachineslist"><h1 id="welcomeheader">{% trans "Welcome to the ocean!" %}</h1><br />
19
    <span class="welcomebody">{% trans "From this panel you will be able to manage your Virtual Machines (VMs). If you don't know what a VM is: take the " %}<a href="#">{% trans "tour" %}</a>.</span><br /><br />
20
    <span class="welcomebody">{% trans "The panel is currently empty, because you don't have any VMs yet. You can start by creating your new VM by clicking the blue button on the right. The wizard will guide you through the hole process." %}</span><br /><br />
21
    <span class="welcomefooter">{% trans "For more information or help, click " %}<a href="#">{% trans "here" %}</a>.</span>
22
</div>
23

    
24
<!-- the form -->
25
<form action="#">
26
        <!-- scrollable root element -->
27
        <div class="modal" id="wizard">
28
                <!-- status bar -->
29
                <ul id="status">
30
                        <li class="active"><span class="headernumber" class="first">1</span><div class="headerbody first">{% trans "Image" %}</div></li>
31
                        <li><span class="headernumber">2</span><div class="headerbody">{% trans "Flavor" %}</div></li>
32
                        <li class="third"><span class="headernumber">3</span><div class="headerbody">{% trans "Name" %}</div></li>
33
                </ul>
34
                <!-- scrollable items -->
35
                <div class="items">
36
                        <!-- pages -->
37
                        <div class="page">
38
                <h2>{% trans "Select an OS" %}</h2>
39
                <hr class="topruler" />
40
                <ul class="tabs">
41
                    <li><a href="#">{% trans "system images" %}</a></li>
42
                    <li><a href="#">{% trans "custom images" %}</a></li>
43
                </ul>
44
                <div class="panes">
45
                            <li id="image-template" style="display:none">
46
                                    <label for="image.id"> 
47
                            <a>
48
                                <div class="image-container">
49
                                    <div class="image">
50
                                        <input class="radio" type="radio" name="image-id" id="image-id" />
51
                                        <img src="" class="image-logo"/>
52
                                        <strong class="image-title">image.title</strong>
53
                                        <br />
54
                                        <span class="description">image.description</span> 
55
                                        <span id="size" class="size">?? MB</span><span class="size"> MB</span>                         
56
                                    </div>
57
                                </div>  
58
                            </a>
59
                                    </label>
60
                            </li>
61
                    <ul class="pane" id="standard-images">
62
                                            <!-- standard images -->
63
                                    </ul>
64
                    <ul class="pane" id="custom-images">
65
                                            <!-- custom images -->
66
                    </ul>
67
                </div>
68
                <hr class="bottomruler" />
69
                                <button type="button" class="prev" id="cancel">{% trans "Cancel" %}</button>
70
                                <button type="button" class="next right">{% trans "Next" %}</button>
71
            </div>
72
                        <div class="page">
73
                                <h2>{% trans "Select CPUs, RAM and Disk Size" %}</h2>
74
                <hr class="topruler" />
75
                <ul>
76
                    <li id="machinetype">
77
                        <div class="machine-type">
78
                            <label for="small" id="small">
79
                                <input type="radio" id="small" name="machine-type" value="small" checked="true" />
80
                                <span class="typebody" id="small-body">{% trans "small" %}</span>
81
                            </label>
82
                        </div>
83
                        <div class="machine-type">      
84
                            <label for="medium" id="medium">
85
                                <input type="radio" id="medium" name="machine-type" value="medium" />                  
86
                                <span class="typebody" id="medium-body">{% trans "medium" %}</span>
87
                            </label>
88
                        </div>
89
                        <div class="machine-type">
90
                            <label for="large" id="large">
91
                                <input type="radio" id="large" name="machine-type" value="large" />
92
                                <span class="typebody" id="large-body">{% trans "large" %}</span>
93
                            </label>
94
                        </div>
95
                        <div class="machine-type">
96
                            <label for="custom" id="custom">
97
                                <input type="radio" name="machine-type" id="custom" value="large" />
98
                                <span class="typebody" id="custom-body">{% trans "custom" %}</span>
99
                            </label>
100
                        </div>
101
                    </li>
102
                    <div id="page2-container">
103
                        <li class="slider-container">
104
                                        <label><strong class="sliders">CPUs</strong></label>
105
                            <input type="range" id="cpu" style="display:none" />
106
                            <input type="text" class="range" id="cpu-indicator" />
107
                                        <span class="units">cores</span>
108
                        </li>
109
                        <li class="slider-container">
110
                                        <label><strong class="sliders">RAM</strong></label>
111
                            <input type="range" id="ram" style="display:none" />
112
                            <input type="text" class="range" id="ram-indicator" />
113
                                        <span class="units">MB</span>
114
                        </li>
115
                        <li class="slider-container">
116
                                    <label><strong class="sliders">Size</strong></label>
117
                            <input type="range" id="storage" style="display:none" />
118
                            <input type="text" class="range" id="storage-indicator" />
119
                                        <span class="units">GB</span>
120
                        </li>
121
                        <li>
122
                            <div class="cost">
123
                                <span> {% trans "Your wallet:" %} 10,000 Credits </span> | <span>{% trans "This setup will cost you:" %}<input type="text" id="credits-indicator" value="20" class="range" /> {% trans "C/hour" %}</span>
124
                            </div>
125
                        </li>
126
                    </div>
127
                </ul>
128
                <hr class="bottomruler" />
129
                                <button type="button" class="prev">{% trans "Back" %}</button>
130
                                <button type="button" class="next right">{% trans "Next" %}</button>
131
            </div>
132
                        <div class="page">
133
                                <h2>{% trans "Confirm your settings" %}</h2>
134
                <hr class="topruler" />
135
                <ul id="page3-container">
136
                    <li class="required" id="label-name">
137
                        <label>
138
                            <strong>Name:</strong>
139
                            <input type="text" class="text" name="machine_name" id="name" value="My Ubuntu 10.04 x86_64 server"/>
140
                        </label>
141
                    </li>
142
                    <li>
143
                        <span>{% trans "Image:" %}</span> <span id="machine_image-label">Ubuntu 10.04 x86_64 server</span>
144
                    </li>
145
                    <li>
146
                        <span>{% trans "CPUs:" %}</span> <span id="machine_cpu-label">2</span> <span>{% trans "cores" %}</span>
147
                    </li>
148
                    <li>
149
                        <span>{% trans "RAM:" %}</span> <span id="machine_ram-label">1024</span><span>MB</span>
150
                    </li>
151
                    <li>
152
                        <span>{% trans "System Disk:" %}</span> <span id="machine_storage-label">10</span><span>GB</span>
153
                    </li>
154
                    <li>
155
                        <span>{% trans "Cost per Hour:" %}</span> <span>40 {% trans "credits" %}</span>
156
                    </li>
157
                    <li>
158
                        <span>{% trans "Credits in Wallet:" %}</span> <span>10.000</span>
159
                    </li>
160
                </ul>
161
                <hr class="bottomruler" />
162
                                <button type="button" class="prev">{% trans "Back" %}</button>
163
                                <button type="button" class="next right" id="start">{% trans "Create VM" %}</button>        
164
            </div>
165
                </div>
166
        </div>
167
</form>
168

    
169
<!-- notification after wizard completion -->
170
<a id="notification" rel="#error-success" href="#"></a>
171

    
172
<div class="modal" id="error-success">
173
    <h3>{% trans "Error!/Success!" %}</h3>
174
    <div><p>{% trans "More details about the result"%}</p></div>
175
</div>
176

    
177
<!-- confirmation before executing an action -->
178
<a id="confirmation" rel="#yes-no" href="#"></a>
179

    
180
<div class="modal" id="yes-no">
181
    <h3>{% trans "You are about to xxx machine yyy" %}</h3>
182
    <p>{% trans "Are you sure you want to proceed?" %}</p>
183
    <button>{% trans "Yes" %}</button>
184
        <button>{% trans "No" %}</button>
185
</div>
186

    
187
<div id="machinesview"></div>
188

    
189
<div class="confirm_multiple">
190
    <p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p>
191
    <button class="yes">{% trans "Confirm All" %}</button>
192
        <button class="no">{% trans "Cancel All" %}</button>
193
</div>
194

    
195
<div id="machines" class="separator"></div>
196

    
197
<script>
198
//add hover to labels
199
$('span.typebody').mouseover(function() {
200
    $(this).addClass('typehover');
201
});
202
$('span.typebody').mouseout(function() {
203
    $(this).removeClass('typehover');
204
});
205

206
// return value from metadata key "OS", if it exists
207
function os_icon(metadata) {
208
    if (!metadata) {
209
        return 'unknown';
210
    }
211

212
    if (metadata.values.OS == undefined || metadata.values.OS == '') {
213
        return 'unknown';
214
    } else {
215
        return metadata.values.OS;
216
    }
217
} 
218

219
// switch to list view
220
$("a#list").click(function(){
221
    list_view(); 
222
    return false;
223
});
224

225

226
// switch to standard view
227
$("a#standard").click(function(){
228
    standard_view();
229
    return false;
230
});
231

232
// launch VM creation wizard
233
$("a#create").click(function(){
234
    // launch wizard only if images and flavors are found
235
    if (images.length > 0  && flavors.length > 0) {
236
        $("#wizard").scrollable().begin();
237
        $("#wizard").show();
238
        $('a#create').data('overlay').load()   
239
    } else if (images.length == 0 ) {
240
        ajax_error('NO_IMAGES');
241
        return false;   
242
    } else if (flavors.length == 0) {
243
        ajax_error('NO_FLAVORS');
244
        return false;
245
    }
246
});
247

248
// create wizard overlay
249
$(function() { 
250
    $("a#create").overlay({
251
        mask: '#000', 
252
        effect: 'default', 
253
        top: '5%', 
254
        oneInstance: false,
255
        closeOnClick: false
256
    });
257
});
258

259
// wizard
260
$(function() {
261
    var root = $("#wizard").scrollable();
262
    var api = root.scrollable();
263
    // rangeinput with default configuration
264
    // validation logic is done inside the onBeforeSeek callback
265
    api.onBeforeSeek(function(event, i) {
266
            // we are going 1 step backwards so no need for validation
267
            if (api.getIndex() < i) {
268
             // 1. get current page
269
                     var page = root.find(".page").eq(api.getIndex()),
270
                         // 2. .. and all required fields inside the page
271
                         inputs = page.find(".required :input").removeClass("error"),
272
                         // 3. .. which are empty
273
                         empty = inputs.filter(function() {
274
                                return $(this).val().replace(/\s*/g, '') == '';
275
                         });
276
                     // if there are empty fields, then
277
                    if (empty.length) {
278
                            // add a CSS class name "error" for empty & required fields
279
                            empty.addClass("error");
280
                            // cancel seeking of the scrollable by returning false
281
                            return false;
282
                    // everything is good
283
                    } 
284
            }
285
            // update status bar
286
            $("#status li").removeClass("active").eq(i).addClass("active");
287
        // update confirm step
288
        if (api.getIndex()==0) {
289
            var image = $("input[type=radio][name=image-id]:checked");
290
            var imageRef = image.length ? image[0].id : false
291
            if (imageRef) {
292
                var imageName = $("label[for=" + imageRef + "] .image-title").text();
293
                $("#machine_image-label")[0].textContent = imageName;
294
                $("input[type=text][name=machine_name]")[0].value = "My " + imageName + " server";
295
            }
296
        } else if (api.getIndex()==1) {
297
            $("#machine_cpu-label")[0].textContent = $("#cpu-indicator")[0].value;
298
            $("#machine_ram-label")[0].textContent = $("#ram-indicator")[0].value;
299
            $("#machine_storage-label")[0].textContent = $("#storage-indicator")[0].value;
300
        }    
301
    });
302
    // if tab is pressed on the next button seek to next page
303
    $(root).live('keydown', function (e) {
304
       if ( e.keyCode == 9 ){
305
           if(e.preventDefault) {
306
               e.preventDefault();
307
           }
308
           api.next();
309
        }
310
    });
311
    $("#name").keypress(function (e) {
312
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
313
                        $('#start').click();
314
                        return false;
315
                } else {
316
                        return true;
317
                }
318
    });
319
});
320

321
// disable sliders in flavor selection
322
function disableSliders() {
323
    $("#cpu").attr('disabled',true);
324
    $("#ram").attr('disabled',true);
325
    $("#storage").attr('disabled',true);
326
}
327

328
//update radio button when clicking on text
329
$("#small-body").live('click' ,function() { 
330
    $(this).parent().find("#small").click();
331
});
332
$("#medium-body").live('click' ,function() { 
333
    $(this).parent().find("#medium").click();
334
});
335
$("#large-body").live('click' ,function() { 
336
    $(this).parent().find("#large").click();
337
});
338
$("#custom-body").live('click' ,function() { 
339
    $(this).parent().find("#custom").click();
340
});
341

342
//select image div on radio button select
343
$('.radio').live('click' ,function() {           
344
    $(this).parents("div").find(".image").removeClass('selecteddiv');
345
    if($(this).is(':checked'))  {
346
        $(this).parent().addClass('selecteddiv');
347
    }
348
});
349

350
// confirm all actions
351
$("div.confirm_multiple .yes").live('click', function(){
352
    while(pending_actions.length > 0){ // if there is a pending action for this server execute it
353
        action = pending_actions.pop(); // extract action
354
        var serverID = action[1];
355
        if ($.cookie("list") != '1') { // standard view
356
            $('#' + serverID + ' .selected').removeClass('selected');
357
            $('#' + serverID + ' .display').removeClass('display');
358
            if (action[0] == shutdown) {
359
                $('#' + serverID + ' .status').text('Shutting down');
360
            } else if (action[0] == start) {
361
                $('#' + serverID + ' .status').text('Starting');
362
            } else if (action[0] == reboot) {
363
                $('#' + serverID + ' .status').text('Rebooting');
364
            } else if (action[0] == destroy) {
365
                $('#' + serverID + ' .status').text('Destroying');
366
            }
367
            $('#' + serverID + ' .spinner').show();
368
        } else { // list view
369
            osIcon = $('#'+serverID).parent().parent().find('.list-logo');
370
            osIcon.attr('os',osIcon.attr('src'));
371
            osIcon.attr('src','static/progress.gif');
372
            if (action[0] == shutdown) {
373
                $('#' + serverID).parent().parent().find('span.status').text('Shutting down');
374
            } else if (action[0] == start) {
375
                $('#' + serverID).parent().parent().find('span.status').text('Starting');
376
            } else if (action[0] == reboot) {
377
                $('#' + serverID).parent().parent().find('span.status').text('Rebooting');
378
            } else if (action[0] == destroy) {
379
                $('#' + serverID).parent().parent().find('span.status').text('Destroying');
380
            }
381
        }
382
        action[0]([serverID]); // execute action
383
    }
384
    update_confirmations();    
385
});
386

387
// cancel all actions
388
$("div.confirm_multiple .no").live('click', function(){
389
    pending_actions = [];
390
    $('.machine .selected').removeClass('selected');
391
    $('.machine .display').removeClass('display');
392
    update_confirmations();
393
});
394

395
// validate cpu input box
396
$("#cpu-indicator").live('change',function(){
397
    var v = Number(this.value);
398
    var i = cpus.indexOf(v);
399
    if (isNaN(v)) {
400
        $(this).value = cpus[0];
401
        $("#cpu").data('rangeinput').setValue(0);
402
    } else if (i == -1) {
403
        for (var j=0; j < cpus.length; j++)
404
            if (v<cpus[j])
405
                break;
406
        $("#cpu").data('rangeinput').setValue(j);
407
    } else {
408
        $("#cpu").data('rangeinput').setValue(i);
409
    }   
410
    return false;
411
});
412

413
// validate ram input box
414
$("#ram-indicator").live('change',function(){
415
    var v = Number(this.value);
416
    var i = ram.indexOf(v);
417
    if (isNaN(v)) {
418
        $(this).value = cpus[0];
419
        $("#ram").data('rangeinput').setValue(0);
420
    } else if (i == -1) {
421
        for (var j=0; j < ram.length; j++)
422
            if (v<ram[j])
423
                break;
424
        $("#ram").data('rangeinput').setValue(j);
425
    } else {
426
        $("#ram").data('rangeinput').setValue(i);
427
    }   
428
    return false;
429
});
430

431

432
// validate storage input box
433
$("#storage-indicator").live('change',function(){
434
    var v = Number(this.value);
435
    var i = disks.indexOf(v);
436
    if (isNaN(v)) {
437
        $(this).value = disks[0];
438
        $("#storage").data('rangeinput').setValue(0);
439
    } else if (i == -1) {
440
        for (var j=0; j < disks.length; j++)
441
            if (v<disks[j])
442
                break;
443
        $("#storage").data('rangeinput').setValue(j);
444
    } else {
445
        $("#storage").data('rangeinput').setValue(i);
446
    }   
447
    return false;
448
});
449

450
// selecting the small size
451
$("#small").click(function(){
452
    $("#cpu").data('rangeinput').setValue(0);
453
    $("#ram").data('rangeinput').setValue(0);
454
    $("#storage").data('rangeinput').setValue(0);
455
    $("#cpu-indicator")[0].value = cpus[0];
456
    $("#ram-indicator")[0].value = ram[0];
457
    $("#storage-indicator")[0].value = disks[0];
458
    $("#small").addClass("active");
459
    $("#medium").removeClass("active");    
460
    $("#large").removeClass("active");    
461
    $("#custom").removeClass("active");    
462
});
463

464
// selecting the medium size
465
$("#medium").click(function(){
466
    $("#cpu").data('rangeinput').setValue(1);
467
    $("#ram").data('rangeinput').setValue(1);
468
    $("#storage").data('rangeinput').setValue(1);
469
    $("#cpu-indicator")[0].value = cpus[1];
470
    $("#ram-indicator")[0].value = ram[1];
471
    $("#storage-indicator")[0].value = disks[1];  
472
    $("#medium").addClass("active");  
473
    $("#small").removeClass("active");    
474
    $("#large").removeClass("active");    
475
    $("#custom").removeClass("active");  
476
});
477

478
// selecting the large size
479
$("#large").click(function(){
480
    $("#cpu").data('rangeinput').setValue(2);
481
    $("#ram").data('rangeinput').setValue(2);
482
    $("#storage").data('rangeinput').setValue(2);
483
    $("#cpu-indicator")[0].value = cpus[2];
484
    $("#ram-indicator")[0].value = ram[2];
485
    $("#storage-indicator")[0].value = disks[2];   
486
    $("#large").addClass("active"); 
487
    $("#medium").removeClass("active");    
488
    $("#small").removeClass("active");    
489
    $("#custom").removeClass("active");  
490
});
491

492
// selecting the custom flavor enables the sliders
493
$("#custom").click(function(){
494
    $("#cpu").attr('disabled',false);
495
    $("#ram").attr('disabled',false);
496
    $("#storage").attr('disabled',false);
497
    $("strong.sliders").style = 'color: #778899;';
498
    $("#custom").addClass("active"); 
499
    $("#medium").removeClass("active");    
500
    $("#large").removeClass("active");    
501
    $("#small").removeClass("active");  
502
});
503

504
// exit the wizard
505
$("#cancel").click(function(){
506
    $("a#create").overlay().close();
507
});
508

509
// starting a new VM through the wizard
510
$("#start").click(function(){
511
    var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');   
512
    var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
513
    var machineName = $('input[name=machine_name]')[0].value;
514

515
    create_vm(machineName, imageRef, flavorRef);
516

517
    $('a#create').data('overlay').close();
518
    $("#emptymachineslist").hide();
519

520
    try{console.warn('creating ' + $("input[name=machine_name]")[0].value)} catch(err){}
521

522
    $("#wizard").hide();
523
});
524

525
// basic functions executed on page load
526
if (images.length > 0) {
527
    // populate image list
528
    update_wizard_images();
529
}
530
if (flavors.length > 0) {
531
    // configure flavors
532
    update_wizard_flavors(); 
533
}
534
// create tabs for main menu
535
$("ul.tabs").tabs("div.panes ul");
536

    
537
</script>