Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ 1bea7ca4

History | View | Annotate | Download (22.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
    <a id="list" href="/machines/list"></a>
15
    <a id="single" href="#"></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" disabled="disabled" /> {% 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
<!-- base notification for error/success reporting -->
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

    
178
<a id="meta-editor-1" rel="#editor-1" href="#"></a>
179

    
180
<div class="meta-modal" id="editor-1">
181
    <h3>
182
        <label>{% trans "Metadata for machine:" %}</label>
183
        <span></span>
184
    </h3>
185
    <hr class="topruler" />
186
    <hr class="fatruler" />
187
    <div class="content">
188
        <ul>
189
            <li class="meta-template">
190
                <label>{% trans "Metadata key" %}</label>
191
                <button type="button" class="remove">{% trans "remove x" %}</button>
192
                <hr class="meta-separator">
193
                <p>{% trans "Metadata value" %}</p>
194
                <button type="button" class="edit">{% trans "edit" %}</button>
195
            </li>
196
        </ul>
197
    </div>
198
    <button type="button" class="create">{% trans "Create New+" %}</button>
199
    <div class="bottomruler" /> 
200
</div>
201

    
202
<a id="meta-editor-2" rel="#editor-2" href="#"></a>
203

    
204
<div class="meta-modal" id="editor-2">
205
    <h3>
206
        <label>{% trans "Metadata for machine:" %}</label>
207
        <span></span>
208
    </h3>
209
    <hr class="topruler" />
210
    <hr class="fatruler" />
211
    <div class="content">
212
        <label class="meta-key">{% trans "Key:" %}</label>
213
        <input type="text" maxlength="15" class="key" value="max 15 characters"/>
214
        <hr class="meta-separator">
215
        <label class="meta-value">{% trans "Value:" %}</label>
216
        <input type="text" maxlength="150" class="value" value="max 150 characters"/>
217
    </div>
218
    <button type="button" class="cancel">{% trans "Cancel" %}</button>
219
    <button type="button" class="save">{% trans "Save" %}</button>
220
    <div class="bottomruler" /> 
221
</div>
222

    
223
<div id="machinesview"></div>
224

    
225
<div class="confirm_multiple">
226
    <p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p>
227
    <button class="yes">{% trans "Confirm All" %}</button>
228
        <button class="no">{% trans "Cancel All" %}</button>
229
</div>
230

    
231
<div id="machines" class="separator"></div>
232

    
233
<script>
234
//add hover to labels
235
$('span.typebody').mouseover(function() {
236
    $(this).addClass('typehover');
237
});
238
$('span.typebody').mouseout(function() {
239
    $(this).removeClass('typehover');
240
});
241

242
// return value from metadata key "OS", if it exists
243
function os_icon(metadata) {
244
    if (!metadata) {
245
        return 'unknown';
246
    }
247

248
    if (metadata.values.OS == undefined || metadata.values.OS == '') {
249
        return 'unknown';
250
    } else {
251
        return metadata.values.OS;
252
    }
253
} 
254

255
// switch to list view
256
$("a#list").click(function(){
257
    list_view(); 
258
    return false;
259
});
260

261
// switch to standard view
262
$("a#standard").click(function(){
263
    standard_view();
264
    return false;
265
});
266

267
// launch VM creation wizard
268
$("a#create").click(function(){
269
    // launch wizard only if images and flavors are found
270
    if (images.length > 0  && flavors.length > 0) {
271
        $("#wizard").scrollable().begin();
272
        $("#wizard").show();
273
        $('a#create').data('overlay').load()   
274
    } else if (images.length == 0 ) {
275
        ajax_error('NO_IMAGES');
276
        return false;   
277
    } else if (flavors.length == 0) {
278
        ajax_error('NO_FLAVORS');
279
        return false;
280
    }
281
});
282

283
// create wizard overlay
284
$(function() { 
285
    $("a#create").overlay({
286
        mask: '#000', 
287
        effect: 'default', 
288
        top: '5%', 
289
        oneInstance: false,
290
        closeOnClick: false
291
    });
292
});
293

294
// wizard
295
$(function() {
296
    var root = $("#wizard").scrollable();
297
    var api = root.scrollable();
298
    // rangeinput with default configuration
299
    // validation logic is done inside the onBeforeSeek callback
300
    api.onBeforeSeek(function(event, i) {
301
            // we are going 1 step backwards so no need for validation
302
            if (api.getIndex() < i) {
303
             // 1. get current page
304
                     var page = root.find(".page").eq(api.getIndex()),
305
                         // 2. .. and all required fields inside the page
306
                         inputs = page.find(".required :input").removeClass("error"),
307
                         // 3. .. which are empty
308
                         empty = inputs.filter(function() {
309
                                return $(this).val().replace(/\s*/g, '') == '';
310
                         });
311
                     // if there are empty fields, then
312
                    if (empty.length) {
313
                            // add a CSS class name "error" for empty & required fields
314
                            empty.addClass("error");
315
                            // cancel seeking of the scrollable by returning false
316
                            return false;
317
                    // everything is good
318
                    } 
319
            }
320
            // update status bar
321
            $("#status li").removeClass("active").eq(i).addClass("active");
322
        // update confirm step
323
        if (api.getIndex()==0) {
324
            var image = $("input[type=radio][name=image-id]:checked");
325
            var imageRef = image.length ? image[0].id : false
326
            if (imageRef) {
327
                var imageName = $("label[for=" + imageRef + "] .image-title").text();
328
                $("#machine_image-label")[0].textContent = imageName;
329
                $("input[type=text][name=machine_name]")[0].value = "My " + imageName + " server";
330
            }
331
        } else if (api.getIndex()==1) {
332
            $("#machine_cpu-label")[0].textContent = $("#cpu-indicator")[0].value;
333
            $("#machine_ram-label")[0].textContent = $("#ram-indicator")[0].value;
334
            $("#machine_storage-label")[0].textContent = $("#storage-indicator")[0].value;
335
        }    
336
    });
337
    // if tab is pressed on the next button seek to next page
338
    $(root).live('keydown', function (e) {
339
       if ( e.keyCode == 9 ){
340
           if(e.preventDefault) {
341
               e.preventDefault();
342
           }
343
           if (api.getIndex() < 2) {
344
               api.next();
345
            } else {
346
                return false;
347
            }
348
        }
349
    });
350
    $("#name").keypress(function (e) {
351
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
352
                        $('#start').click();
353
                        return false;
354
                } else {
355
                        return true;
356
                }
357
    });
358
});
359

360
// disable sliders in flavor selection
361
function disableSliders() {
362
    $("#cpu").attr('disabled',true);
363
    $("#ram").attr('disabled',true);
364
    $("#storage").attr('disabled',true);
365
}
366

367
//update radio button when clicking on text
368
$("#small-body").live('click' ,function() { 
369
    $(this).parent().find("#small").click();
370
});
371
$("#medium-body").live('click' ,function() { 
372
    $(this).parent().find("#medium").click();
373
});
374
$("#large-body").live('click' ,function() { 
375
    $(this).parent().find("#large").click();
376
});
377
$("#custom-body").live('click' ,function() { 
378
    $(this).parent().find("#custom").click();
379
});
380

381
//select image div on radio button select
382
$('.radio').live('click' ,function() {           
383
    $(this).parents("div").find(".image").removeClass('selecteddiv');
384
    if($(this).is(':checked'))  {
385
        $(this).parent().addClass('selecteddiv');
386
    }
387
});
388

389
// confirm all actions
390
$("div.confirm_multiple .yes").live('click', function(){
391
    while(pending_actions.length > 0){ // if there is a pending action for this server execute it
392
        action = pending_actions.pop(); // extract action
393
        var serverID = action[1];
394
        if ($.cookie("list") != '1') { // standard view
395
            $('#' + serverID + ' .selected').removeClass('selected');
396
            $('#' + serverID + ' .display').removeClass('display');
397
            if (action[0] == shutdown) {
398
                $('#' + serverID + ' .status').text('Shutting down');
399
            } else if (action[0] == start) {
400
                $('#' + serverID + ' .status').text('Starting');
401
            } else if (action[0] == reboot) {
402
                $('#' + serverID + ' .status').text('Rebooting');
403
            } else if (action[0] == destroy) {
404
                $('#' + serverID + ' .status').text('Destroying');
405
            }
406
            $('#' + serverID + ' .spinner').show();
407
        } else { // list view
408
            osIcon = $('#'+serverID).parent().parent().find('.list-logo');
409
            osIcon.attr('os',osIcon.attr('src'));
410
            osIcon.attr('src','static/progress.gif');
411
            if (action[0] == shutdown) {
412
                $('#' + serverID).parent().parent().find('span.status').text('Shutting down');
413
            } else if (action[0] == start) {
414
                $('#' + serverID).parent().parent().find('span.status').text('Starting');
415
            } else if (action[0] == reboot) {
416
                $('#' + serverID).parent().parent().find('span.status').text('Rebooting');
417
            } else if (action[0] == destroy) {
418
                $('#' + serverID).parent().parent().find('span.status').text('Destroying');
419
            }
420
        }
421
        action[0]([serverID]); // execute action
422
    }
423
    update_confirmations();    
424
});
425

426
// cancel all actions
427
$("div.confirm_multiple .no").live('click', function(){
428
    pending_actions = [];
429
    $('.machine .selected').removeClass('selected');
430
    $('.machine .display').removeClass('display');
431
    update_confirmations();
432
});
433

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

452
// validate ram input box
453
$("#ram-indicator").live('change',function(){
454
    var v = Number(this.value);
455
    var i = ram.indexOf(v);
456
    if (isNaN(v)) {
457
        $(this).value = cpus[0];
458
        $("#ram").data('rangeinput').setValue(0);
459
    } else if (i == -1) {
460
        for (var j=0; j < ram.length; j++)
461
            if (v<ram[j])
462
                break;
463
        $("#ram").data('rangeinput').setValue(j);
464
    } else {
465
        $("#ram").data('rangeinput').setValue(i);
466
    }   
467
    return false;
468
});
469

470

471
// validate storage input box
472
$("#storage-indicator").live('change',function(){
473
    var v = Number(this.value);
474
    var i = disks.indexOf(v);
475
    if (isNaN(v)) {
476
        $(this).value = disks[0];
477
        $("#storage").data('rangeinput').setValue(0);
478
    } else if (i == -1) {
479
        for (var j=0; j < disks.length; j++)
480
            if (v<disks[j])
481
                break;
482
        $("#storage").data('rangeinput').setValue(j);
483
    } else {
484
        $("#storage").data('rangeinput').setValue(i);
485
    }   
486
    return false;
487
});
488

489
// selecting the small size
490
$("#small").click(function(){
491
    $("#cpu").data('rangeinput').setValue(0);
492
    $("#ram").data('rangeinput').setValue(0);
493
    $("#storage").data('rangeinput').setValue(0);
494
    $("#cpu-indicator")[0].value = cpus[0];
495
    $("#ram-indicator")[0].value = ram[0];
496
    $("#storage-indicator")[0].value = disks[0];
497
    $("#small").addClass("active");
498
    $("#medium").removeClass("active");    
499
    $("#large").removeClass("active");    
500
    $("#custom").removeClass("active");    
501
});
502

503
// selecting the medium size
504
$("#medium").click(function(){
505
    $("#cpu").data('rangeinput').setValue(1);
506
    $("#ram").data('rangeinput').setValue(1);
507
    $("#storage").data('rangeinput').setValue(1);
508
    $("#cpu-indicator")[0].value = cpus[1];
509
    $("#ram-indicator")[0].value = ram[1];
510
    $("#storage-indicator")[0].value = disks[1];  
511
    $("#medium").addClass("active");  
512
    $("#small").removeClass("active");    
513
    $("#large").removeClass("active");    
514
    $("#custom").removeClass("active");  
515
});
516

517
// selecting the large size
518
$("#large").click(function(){
519
    $("#cpu").data('rangeinput').setValue(2);
520
    $("#ram").data('rangeinput').setValue(2);
521
    $("#storage").data('rangeinput').setValue(2);
522
    $("#cpu-indicator")[0].value = cpus[2];
523
    $("#ram-indicator")[0].value = ram[2];
524
    $("#storage-indicator")[0].value = disks[2];   
525
    $("#large").addClass("active"); 
526
    $("#medium").removeClass("active");    
527
    $("#small").removeClass("active");    
528
    $("#custom").removeClass("active");  
529
});
530

531
// selecting the custom flavor enables the sliders
532
$("#custom").click(function(){
533
    $("#cpu").attr('disabled',false);
534
    $("#ram").attr('disabled',false);
535
    $("#storage").attr('disabled',false);
536
    $("strong.sliders").style = 'color: #778899;';
537
    $("#custom").addClass("active"); 
538
    $("#medium").removeClass("active");    
539
    $("#large").removeClass("active");    
540
    $("#small").removeClass("active");  
541
});
542

543
//when textbox gains focus, add selection in css
544
$('#cpu-indicator').focus(function() {
545
    $(this).addClass('selectedrange');
546
});
547
$('#ram-indicator').focus(function() {
548
    $(this).addClass('selectedrange');
549
});
550
$('#storage-indicator').focus(function() {
551
    $(this).addClass('selectedrange');
552
});
553

554
//when textbox loses focus, clear selection in css
555
$('#cpu-indicator').blur(function() {
556
    $(this).removeClass('selectedrange');
557
});
558
$('#ram-indicator').blur(function() {
559
    $(this).removeClass('selectedrange');
560
});
561
$('#storage-indicator').blur(function() {
562
    $(this).removeClass('selectedrange');
563
});
564

565
// exit the wizard
566
$("#cancel").click(function(){
567
    $("a#create").overlay().close();
568
});
569

570
// starting a new VM through the wizard
571
$("#start").click(function(){
572
    var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');   
573
    var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
574
    var machineName = $('input[name=machine_name]')[0].value;
575

576
    create_vm(machineName, imageRef, flavorRef);
577

578
    $('a#create').data('overlay').close();
579
    $("#emptymachineslist").hide();
580

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

583
    $("#wizard").hide();
584
});
585

586
// basic functions executed on page load
587
if (images.length > 0) {
588
    // populate image list
589
    update_wizard_images();
590
}
591
if (flavors.length > 0) {
592
    // configure flavors
593
    update_wizard_flavors(); 
594
}
595
// create tabs for main menu
596
$("ul.tabs").tabs("div.panes ul");
597

    
598
</script>