Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ 66edd851

History | View | Annotate | Download (20.5 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><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 "your 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="imageGroup" 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.find("button.next").keydown(function(e) {
304
            if (e.keyCode == 9) {
305
                    // seeks to next tab by executing our validation routine
306
                    api.next();
307
                    e.preventDefault();
308
            }
309
    });
310
    $("#name").keypress(function (e) {
311
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
312
                        $('#start').click();
313
                        return false;
314
                } else {
315
                        return true;
316
                }
317
    });
318
});
319

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

327
if($('.radio:checked').val() == 'true')  {
328
    $(this).parent().addClass('selecteddiv');
329
}
330

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

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

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

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

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

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

434

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

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

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

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

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

507
// exit the wizard
508
$("#cancel").click(function(){
509
    $("a#create").overlay().close();
510
});
511

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

518
    create_vm(machineName, imageRef, flavorRef);
519

520
    $('a#create').data('overlay').close();
521
    $("#emptymachineslist").hide();
522

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

525
    $("#wizard").hide();
526
});
527

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

    
540
</script>