Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_create_view.js @ 426e1fb9

History | View | Annotate | Download (54.5 kB)

1
// Copyright 2011 GRNET S.A. All rights reserved.
2
// 
3
// Redistribution and use in source and binary forms, with or
4
// without modification, are permitted provided that the following
5
// conditions are met:
6
// 
7
//   1. Redistributions of source code must retain the above
8
//      copyright notice, this list of conditions and the following
9
//      disclaimer.
10
// 
11
//   2. Redistributions in binary form must reproduce the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer in the documentation and/or other materials
14
//      provided with the distribution.
15
// 
16
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
28
// 
29
// The views and conclusions contained in the software and
30
// documentation are those of the authors and should not be
31
// interpreted as representing official policies, either expressed
32
// or implied, of GRNET S.A.
33
// 
34

    
35
;(function(root){
36

    
37
    // root
38
    var root = root;
39
    
40
    // setup namepsaces
41
    var snf = root.synnefo = root.synnefo || {};
42
    var models = snf.models = snf.models || {}
43
    var storage = snf.storage = snf.storage || {};
44
    var ui = snf.ui = snf.ui || {};
45
    var util = snf.util = snf.util || {};
46

    
47
    var views = snf.views = snf.views || {}
48

    
49
    // shortcuts
50
    var bb = root.Backbone;
51

    
52

    
53
    views.VMCreationPasswordView = views.Overlay.extend({
54
        view_id: "creation_password_view",
55
        content_selector: "#creation-password-overlay",
56
        css_class: 'overlay-password overlay-info',
57
        overlay_id: "creation-password-overlay",
58

    
59
        subtitle: "",
60
        title: "Machine password",
61

    
62
        initialize: function(options) {
63
            views.FeedbackView.__super__.initialize.apply(this, arguments);
64
            _.bindAll(this, 'show_password');
65

    
66
            this.password = this.$("#new-machine-password");
67
            this.copy = this.$(".clipboard");
68

    
69
            this.$(".show-machine").click(_.bind(function(){
70
                if (this.$(".show-machine").hasClass("in-progress")) {
71
                    return;
72
                }
73
                this.hide();
74
                snf.ui.main.show_vm_details(storage.vms.get(this.vm_id));
75
            }, this));
76

    
77
            _.bindAll(this, "handle_vm_added");
78
            storage.vms.bind("add", this.handle_vm_added);
79
            this.password.text("");
80
        },
81

    
82
        handle_vm_added: function() {
83
            this.$(".show-machine").removeClass("in-progress");
84
        },
85
        
86
        show_password: function() {
87
            this.$(".show-machine").addClass("in-progress");
88
            this.password.text(this.pass);
89
            if (storage.vms.get(this.vm_id)) {
90
                this.$(".show-machine").removeClass("in-progress");
91
            }
92
            
93
            this.clip = new snf.util.ClipHelper(this.copy, this.pass);
94
        },
95

    
96
        onClose: function() {
97
            this.password.text("");
98
            this.vm_id = undefined;
99
            try { delete this.clip; } catch (err) {};
100
        },
101
        
102
        beforeOpen: function() {
103
            this.copy.empty();
104
        },
105
        
106
        onOpen: function() {
107
            this.show_password();
108
        },
109

    
110
        show: function(pass, vm_id) {
111
            this.pass = pass;
112
            this.vm_id = vm_id;
113
            
114
            views.VMCreationPasswordView.__super__.show.apply(this, arguments);
115
        }
116
    })
117

    
118

    
119
    
120
    views.CreateVMStepView = views.View.extend({
121
        step: "1",
122
        title: "Image",
123
        submit: false,
124

    
125
        initialize: function(view) {
126
            this.parent = view;
127
            this.el = view.$("div.create-step-cont.step-" + this.step);
128
            this.header = this.$(".step-header .step-" + this.step);
129
            this.view_id = "create_step_" + this.step;
130

    
131
            views.CreateVMStepView.__super__.initialize.apply(this);
132
        },
133

    
134
        show: function() {
135
            // show current
136
            this.el.show();
137
            this.header.addClass("current");
138
            this.header.show();
139
            this.update_layout();
140
        },
141

    
142
        reset: function() {
143
        }
144
    })
145

    
146
    views.CreateImageSelectView = views.CreateVMStepView.extend({
147

    
148
        initialize: function() {
149
            views.CreateImageSelectView.__super__.initialize.apply(this, arguments);
150

    
151
            // elements
152
            this.images_list_cont = this.$(".images-list-cont");
153
            this.images_list = this.$(".images-list-cont ul");
154
            this.image_details = this.$(".images-info-cont");
155
            this.image_details_desc = this.$(".images-info-cont .description p");
156
            this.image_details_title = this.$(".images-info-cont h4");
157
            this.image_details_size = this.$(".images-info-cont .size p");
158
            this.image_details_os = this.$(".images-info-cont .os p");
159
            this.image_details_kernel = this.$(".images-info-cont .kernel p");
160
            this.image_details_gui = this.$(".images-info-cont .gui p");
161
            this.image_details_vm = this.$(".images-info-cont .vm-name p");
162

    
163
            this.categories_list = this.$(".category-filters");
164
            
165
            // params initialization
166
            this.type_selections = {"system": "System"};
167
            this.type_selections_order = ['system'];
168
            
169
            this.images_storage = snf.storage.images;
170

    
171
            // apply image service specific image types
172
            if (this.images_storage.type_selections) {
173
                this.type_selections = _.extend(
174
                    this.images_storage.type_selections,
175
                    this.type_selections)
176

    
177
                this.type_selections_order = this.images_storage.type_selections_order;
178
            }
179

    
180
            this.selected_type = undefined;
181
            this.selected_categories = [];
182

    
183
            this.images = [];
184
            this.images_ids = [];
185
            this.custom_images = [];
186

    
187
            // handlers initialization
188
            this.create_types_selection_options();
189
            this.init_handlers();
190
            this.init_position();
191
        },
192
        
193
        init_position: function() {
194
            //this.el.css({position: "absolute"});
195
            //this.el.css({top:"10px"})
196
        },
197
        
198
        init_handlers: function() {
199
            var self = this;
200
            this.types.live("click", function() {
201
                self.select_type($(this).attr("id").replace("type-select-",""));
202
            });
203
            
204
            this.image_details.find(".hide").click(_.bind(function(){
205
                this.hide_image_details();
206
            }, this));
207

    
208
            this.$(".register-custom-image").live("click", function(){
209
                var confirm_close = true;
210
                if (confirm_close) {
211
                    snf.ui.main.custom_images_view.show(self.parent);
212
                } else {
213
                }
214
            })
215

    
216
            $(".image-warning .confirm").bind('click', function(){
217
                $(".image-warning").hide();
218
                $(".create-controls").show();
219
            })
220
        },
221

    
222
        update_images: function(images) {
223
            this.images = images;
224
            this.images_ids = _.map(this.images, function(img){return img.id});
225
            return this.images;
226
        },
227

    
228
        create_types_selection_options: function() {
229
            var list = this.$("ul.type-filter");
230
            _.each(this.type_selections_order, _.bind(function(key) {
231
                list.append('<li id="type-select-{0}">{1}</li>'.format(key, this.type_selections[key]));
232
            }, this));
233
            this.types = this.$(".type-filter li");
234
        },
235

    
236
        update_layout: function() {
237
            if (!this.selected_type) {
238
                this.selected_type = _.keys(this.type_selections)[0];
239
            }
240
            this.select_type(this.selected_type);
241
        },
242
        
243
        get_categories: function(images) {
244
            return [];
245
            return ["Desktop", "Server", "Linux", "Windows"];
246
        },
247

    
248
        reset_categories: function() {
249
            var categories = this.get_categories(this.images);
250
            this.categories_list.find("li").remove();
251

    
252
            _.each(categories, _.bind(function(cat) {
253
                var el = $("<li />");
254
                el.text(cat);
255
                this.categories_list.append(el);
256
            }, this));
257

    
258
            if (!categories.length) { 
259
                this.categories_list.parent().find(".clear").hide();
260
                this.categories_list.parent().find(".empty").show();
261
            } else {
262
                this.categories_list.parent().find(".clear").show();
263
                this.categories_list.parent().find(".empty").hide();
264
            }
265
        },
266
        
267
        show_loading_view: function() {
268
            this.$(".images-list-cont .empty").hide();
269
            this.images_list.hide();
270
            this.$(".images-list-cont .loading").show();
271
            this.$(".images-list-cont .images-list").hide();
272
            this.reset_categories();
273
            this.update_images([]);
274
            this.reset_images();
275
            this.hide_list_loading();
276
        },
277

    
278
        hide_loading_view: function(images) {
279
            this.$(".images-list-cont .loading").hide();
280
            this.$(".images-list-cont .images-list").show();
281
            this.reset_categories();
282
            this.update_images(images);
283
            this.reset_images();
284
            this.select_image(this.selected_image);
285
            this.hide_list_loading();
286
            $(".custom-image-help").hide();
287
            if (this.selected_type == 'personal' && !images.length) {
288
                $(".custom-image-help").show();
289
            }
290

    
291
        },
292

    
293
        select_type: function(type) {
294
            this.selected_type = type;
295
            this.types.removeClass("selected");
296
            this.types.filter("#type-select-" + this.selected_type).addClass("selected");
297
            this.images_storage.update_images_for_type(
298
                this.selected_type, 
299
                _.bind(this.show_loading_view, this), 
300
                _.bind(this.hide_loading_view, this)
301
            );
302

    
303
            this.update_layout_for_type(type);
304
        },
305

    
306
        update_layout_for_type: function(type) {
307
            if (type != "system") {
308
                this.$(".custom-action").hide();
309
            } else {
310
                this.$(".custom-action").hide();
311
            }
312

    
313
        },
314

    
315
        show_list_loading: function() {
316
            this.$(".images-list-cont").addClass("loading");
317
        },
318

    
319
        hide_list_loading: function() {
320
            this.$(".images-list-cont").removeClass("loading");
321
        },
322
        
323
        display_warning_for_image: function(image) {
324
          if (image && !image.is_system_image() && !image.owned_by(synnefo.user)) {
325
            $(".create-vm .image-warning").show();
326
            $(".create-controls").hide();
327
          } else {
328
            $(".create-vm .image-warning").hide();
329
            $(".create-controls").show();
330
          }
331
        },
332

    
333
        select_image: function(image) {
334
            if (image && image.get('id') && !_.include(this.images_ids, image.get('id'))) {
335
                image = undefined;
336
            }
337
            if (!image && this.images_ids.length) {
338
                if (this.selected_image && this.images_ids.indexOf(this.selected_image.id) > -1) {
339
                    image = this.selected_image;
340
                } else {
341
                    image = this.images_storage.get(this.images_ids[0]);
342
                }
343
            }
344
             
345
            // no images select null image so that next button gets hidden
346
            if (!this.images_ids.length) { image = undefined };
347
            
348
            if ((!this.selected_image && image) || (this.selected_image != image))
349
                this.trigger("change", image);
350
                this.display_warning_for_image(image);
351

    
352
            this.selected_image = image;
353
                
354
            if (image) {
355
                this.images_list.find(".image-details").removeClass("selected");
356
                this.images_list.find(".image-details#create-vm-image-" + this.selected_image.id).addClass("selected");
357
                this.update_image_details(image);
358

    
359
            } else {
360
            }
361

    
362
            this.image_details.hide();
363
            this.validate();
364
        },
365

    
366
        update_image_details: function(image) {
367
            this.image_details_desc.hide().parent().hide();
368
            if (image.get_description()) {
369
                this.image_details_desc.html(image.get_description(false)).show().parent().show();
370
            }
371
            var img = snf.ui.helpers.os_icon_tag(image.escape("OS"))
372
            if (image.get("name")) {
373
                this.image_details_title.html(img + image.escape("name")).show().parent().show();
374
            }
375
            
376
            var extra_details = this.image_details.find(".extra-details");
377
            // clean prevously added extra details
378
            extra_details.find(".image-detail").remove();
379
            
380
            var skip_keys = ['description', 'sortorder']
381
            var meta_keys = ['owner', 'OS', 'kernel', 'GUI'];
382
            var detail_tpl = ('<div class="clearfix image-detail {2}">' +
383
                             '<span class="title clearfix">{0}' +
384
                             '<span class="custom">custom</span></span>' +
385
                             '<p class="value">{1}</p>' + 
386
                             '</div>');
387
            meta_keys = _.union(meta_keys, this.images_storage.display_metadata || []);
388
            
389
            var append_metadata_row = function(key, is_extra) {
390
                var value;
391
                var method = 'get_' + key.toLowerCase();
392
                var display_method = 'display_' + key.toLowerCase();
393
                 
394
                if (image[display_method]) {
395
                    value = image[display_method]();
396
                } else if (image[method]) {
397
                    value = image[method]();
398
                } else {
399
                    value = image.get(key);
400

    
401
                    if (!value) {
402
                        value = image.get_meta(key);
403
                    }
404
                }
405
                    
406
                if (!value) { return; }
407
                 
408
                var label = this.images_storage.meta_labels[key];
409
                if (!label) {
410
                    var label = _(key.replace(/_/g," ")).capitalize();
411
                }
412
                var row_cls = key.toLowerCase();
413
                if (is_extra) { row_cls += " extra-meta" };
414
                extra_details.append(detail_tpl.format(_.escape(label), value, row_cls));
415
            }
416

    
417
            _.each(meta_keys, function(key) {
418
                append_metadata_row.apply(this, [key]);
419
            }, this);
420
            
421
            if (synnefo.storage.images.display_extra_metadata) {
422
                _.each(image.get('metadata').values, function(value, key) {
423
                    if (!_.contains(meta_keys, key) && 
424
                        !_.contains(meta_keys, key.toLowerCase()) &&
425
                        !_.contains(meta_keys, key.toUpperCase()) &&
426
                        !_.contains(skip_keys, key)) {
427
                            append_metadata_row.apply(this, [key, true]);
428
                    }
429
                }, this);
430
            }
431
        },
432

    
433
        reset_images: function() {
434
            this.images_list.find("li").remove();
435
            _.each(this.images, _.bind(function(img){
436
                this.add_image(img);
437
            }, this))
438
            
439
            if (this.images.length) {
440
                this.images_list.parent().find(".empty").hide();
441
                this.images_list.show();
442
            } else {
443
                this.images_list.parent().find(".empty").show();
444
                this.images_list.hide();
445
            }
446

    
447
            var self = this;
448
            this.images_list.find(".image-details").click(function(){
449
                self.select_image($(this).data("image"));
450
            });
451
            
452
        },
453

    
454
        show: function() {
455
            this.image_details.hide();
456
            this.parent.$(".create-controls").show();
457

    
458
            views.CreateImageSelectView.__super__.show.apply(this, arguments);
459
        },
460

    
461
        add_image: function(img) {
462
            var image = $(('<li id="create-vm-image-{1}"' +
463
                           'class="image-details clearfix">{2}{0}'+
464
                           '<span class="show-details">details</span>'+
465
                           '<span class="size"><span class="prepend">by </span>{5}</span>' + 
466
                           '<span class="owner">' +
467
                           '<span class="prepend"></span>' +
468
                           '{3}</span>' + 
469
                           '<p>{4}</p>' +
470
                           '</li>').format(img.escape("name"), 
471
                                                  img.id, 
472
                                                  snf.ui.helpers.os_icon_tag(img.escape("OS")),
473
                                                  _.escape(img.get_readable_size()),
474
                                                  util.truncate(img.get_description(false), 35),
475
                                                  _.escape(img.display_owner())));
476
            image.data("image", img);
477
            image.data("image_id", img.id);
478
            this.images_list.append(image);
479
            image.find(".show-details").click(_.bind(function(e){
480
                e.preventDefault();
481
                e.stopPropagation();
482
                this.show_image_details(img);
483
            }, this))
484
        },
485
            
486
        hide_image_details: function() {
487
            this.image_details.fadeOut(200);
488
            this.parent.$(".create-controls").show();
489
        },
490

    
491
        show_image_details: function(img) {
492
            this.parent.$(".create-controls").hide();
493
            this.update_image_details(img);
494
            this.image_details.fadeIn(100);
495
        },
496

    
497
        reset: function() {
498
            this.selected_image = false;
499
            this.select_type("system");
500
        },
501

    
502
        get: function() {
503
            return {'image': this.selected_image};
504
        },
505

    
506
        validate: function() {
507
            if (!this.selected_image) {
508
                this.parent.$(".form-action.next").hide();
509
            } else {
510
                this.parent.$(".form-action.next").show();
511
            }
512
        }
513
    });
514

    
515
    views.CreateFlavorSelectView = views.CreateVMStepView.extend({
516
        step: 2,
517
        initialize: function() {
518
            views.CreateFlavorSelectView.__super__.initialize.apply(this, arguments);
519
            this.parent.bind("image:change", _.bind(this.handle_image_change, this));
520

    
521
            this.cpus = this.$(".flavors-cpu-list");
522
            this.disks = this.$(".flavors-disk-list");
523
            this.disk_templates = this.$(".flavors-disk-template-list");
524
            this.mems = this.$(".flavors-mem-list");
525

    
526
            this.predefined_flavors = SUGGESTED_FLAVORS;
527
            this.predefined_flavors_keys = _.keys(SUGGESTED_FLAVORS);
528
            this.predefined_flavors_keys = _.sortBy(this.predefined_flavors_keys, _.bind(function(k){
529
                var flv = this.predefined_flavors[k];
530
                return (flv.ram * flv.cpu * flv.disk);
531
            }, this));
532

    
533
            this.predefined = this.$(".predefined-list");
534
        },
535

    
536
        handle_image_change: function(data) {
537
            this.current_image = data;
538
            this.update_valid_predefined();
539
            this.current_flavor = undefined;
540
            this.update_flavors_data();
541
            this.update_predefined_flavors();
542
            this.reset_flavors();
543
            this.update_layout();
544
        },
545

    
546
        validate_selected_flavor: function() {
547
            if (!this.flavor_is_valid(this.current_flavor)) {
548
                this.select_valid_flavor();
549
            }
550
        },
551

    
552
        reset_flavors: function() {
553
            this.$(".flavor-opts-list .option").remove();
554
            this.create_flavors();
555
        },
556

    
557
        update_predefined_flavors: function() {
558
            this.predefined.find("li").remove();
559
            _.each(this.predefined_flavors_keys, _.bind(function(key) {
560
                var val = this.predefined_flavors[key];
561
                var el = $(('<li class="predefined-selection" id="predefined-flavor-{0}">' +
562
                           '{1}</li>').format(key, _.escape(_(key).capitalize())));
563

    
564
                this.predefined.append(el);
565
                el.data({flavor: storage.flavors.get_flavor(val.cpu, val.ram, val.disk, val.disk_template, this.flavors)});
566
                el.click(_.bind(function() {
567
                    this.handle_predefined_click(el);
568
                }, this))
569
            }, this));
570
            this.update_valid_predefined();
571
        },
572

    
573
        handle_predefined_click: function(el) {
574
            if (el.hasClass("disabled")) { return };
575
            this.set_current(el.data("flavor"));
576
        },
577

    
578
        select_valid_flavor: function() {
579
            var found = false;
580
            var self = this;
581

    
582
            _.each(["cpu", "mem", "disk"], function(t) {
583
              var el = $(".flavor-options."+t);
584
              var all = el.find(".flavor-opts-list li").length;
585
              var disabled = el.find(".flavor-opts-list li.disabled").length;
586
              if (disabled >= all) {
587
                el.find("h4").addClass("error");
588
              } else {
589
                el.find("h4").removeClass("error");
590
              }
591
            })
592

    
593
            _.each(this.flavors, function(flv) {
594
                if (self.flavor_is_valid(flv)) {
595
                    found = flv;
596
                    return false;
597
                }
598
            });
599
            
600
            if (found) {
601
                this.set_current(found);
602
            } else {
603
                this.current_flavor = undefined;
604
                this.validate();
605
                this.$("li.predefined-selection").addClass("disabled");
606
                this.$(".flavor-opts-list li").removeClass("selected");
607
            }
608
        },
609

    
610
        update_valid_predefined: function() {
611
            this.update_unavailable_values();
612
            var self = this;
613
            this.valid_predefined = _.select(_.map(this.predefined_flavors, function(flv, key){
614
                var existing = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, flv.disk_template, self.flavors);
615
                // non existing
616
                if (!existing) {
617
                    return false;
618
                }
619
                
620
                // not available for image
621
                if (self.unavailable_values && self.unavailable_values.disk.indexOf(existing.get_disk_size()) > -1) {
622
                    return false
623
                }
624

    
625
                return key;
626
            }), function(ret) { return ret });
627
            
628
            $("li.predefined-selection").addClass("disabled");
629
            _.each(this.valid_predefined, function(key) {
630
                $("#predefined-flavor-" + key).removeClass("disabled");
631
            })
632
        },
633

    
634
        update_selected_predefined: function() {
635
            var self = this;
636
            this.predefined.find("li").removeClass("selected");
637

    
638
            _.each(this.valid_predefined, function(key){
639
                var flv = self.predefined_flavors[key];
640
                var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, flv.disk_template, self.flavors);
641

    
642
                if (exists && (exists.id == self.current_flavor.id)) {
643
                    $("#predefined-flavor-" + key).addClass("selected");
644
                }
645
            })
646
        },
647
        
648
        update_flavors_data: function() {
649
            this.flavors = storage.flavors.active();
650
            this.flavors_data = storage.flavors.get_data(this.flavors);
651
            
652
            var self = this;
653
            var set = false;
654
            
655
            // FIXME: validate current flavor
656
            
657
            if (!this.current_flavor) {
658
                _.each(this.valid_predefined, function(key) {
659
                    var flv = self.predefined_flavors[key];
660
                    var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, flv.disk_template, self.flavors);
661
                    if (exists && !set) {
662
                        self.set_current(exists);
663
                        set = true;
664
                    }
665
                })
666
            }
667

    
668
            this.update_unavailable_values();
669
        },
670

    
671
        update_unavailable_values: function() {
672
            
673
            var unavailable = {disk:[], ram:[], cpu:[]}
674
            var user_excluded = {disk:[], ram:[], cpu:[]}
675
            var image_excluded = {disk:[], ram:[], cpu:[]}
676

    
677
            if (this.current_image) {
678
              image_excluded = storage.flavors.unavailable_values_for_image(this.current_image);
679
            }
680

    
681
            quotas = this.get_vm_params_quotas();
682
            user_excluded = storage.flavors.unavailable_values_for_quotas(quotas);
683

    
684
            unavailable.disk = user_excluded.disk.concat(image_excluded.disk);
685
            unavailable.ram = user_excluded.ram.concat(image_excluded.ram);
686
            unavailable.cpu = user_excluded.cpu.concat(image_excluded.cpu);
687
            
688
            this.unavailable_values = unavailable;
689
        },
690
        
691
        get_vm_params_quotas: function() {
692
          var quotas = synnefo.storage.quotas;
693
          var quota = {
694
            'ram': quotas.get('cyclades.ram').get('available'),
695
            'cpu': quotas.get('cyclades.cpu').get('available'),
696
            'disk': quotas.get('cyclades.disk').get('available')
697
          }
698
          return quota;
699
        },
700

    
701
        flavor_is_valid: function(flv) {
702
            if (!flv) { return false };
703

    
704
            var existing = storage.flavors.get_flavor(flv.get("cpu"), flv.get("ram"), flv.get("disk"), flv.get("disk_template"), this.flavors);
705
            if (!existing) { return false };
706
            
707
            if (this.unavailable_values && (this.unavailable_values.disk.indexOf(parseInt(flv.get("disk")) * 1000) > -1)) {
708
                return false;
709
            }
710
            if (this.unavailable_values && (this.unavailable_values.ram.indexOf(parseInt(flv.get("ram"))) > -1)) {
711
                return false;
712
            }
713
            if (this.unavailable_values && (this.unavailable_values.cpu.indexOf(parseInt(flv.get("cpu"))) > -1)) {
714
                return false;
715
            }
716
            return true;
717
        },
718
            
719
        set_valid_current_for: function(t, val) {
720
            var found = this.flavors[0];
721
            _.each(this.flavors, function(flv) {
722
                if (flv.get(t) == val) {
723
                    found = flv;
724
                }
725
            });
726

    
727
            this.set_current(found);
728
            this.validate_selected_flavor();
729
        },
730

    
731
        set_current: function(flv) {
732

    
733
            if (!flv) {
734
                // user clicked on invalid combination
735
                // force the first available choice for the
736
                // type of option he last clicked
737
                this.set_valid_current_for.apply(this, this.last_choice);
738
                return;
739
            }
740

    
741
            this.current_flavor = flv;
742
            this.trigger("change");
743
            if (this.current_flavor) {
744
                this.update_selected_flavor();
745
                this.update_selected_predefined();
746
            }
747
            
748
            this.validate();
749
        },
750
        
751
        select_default_flavor: function() {
752
               
753
        },
754

    
755
        update_selected_from_ui: function() {
756
            this.set_current(this.ui_selected());
757
        },
758
        
759
        update_disabled_flavors: function() {
760
            this.$(".flavor-options.disk li").removeClass("disabled");
761
            if (!this.unavailable_values) { return }
762
            
763
            this.$("#create-vm-flavor-options .flavor-options.disk li").each(_.bind(function(i, el){
764
                var el_value = $(el).data("value") * 1000;
765
                if (this.unavailable_values.disk.indexOf(el_value) > -1) {
766
                    $(el).addClass("disabled");
767
                    $(el).removeClass("selected");
768
                };
769
            }, this));
770

    
771
            this.$("#create-vm-flavor-options .flavor-options.mem li").each(_.bind(function(i, el){
772
                var el_value = $(el).data("value");
773
                if (this.unavailable_values.ram.indexOf(el_value) > -1) {
774
                    $(el).addClass("disabled");
775
                    $(el).removeClass("selected");
776
                };
777
            }, this));
778

    
779
            this.$("#create-vm-flavor-options .flavor-options.cpu li").each(_.bind(function(i, el){
780
                var el_value = $(el).data("value");
781
                if (this.unavailable_values.cpu.indexOf(el_value) > -1) {
782
                    $(el).addClass("disabled");
783
                    $(el).removeClass("selected");
784
                };
785
            }, this));
786
        },
787

    
788
        create_flavors: function() {
789
            var flavors = this.get_active_flavors();
790
            var valid_flavors = this.get_valid_flavors();
791
            this.__added_flavors = {'cpu':[], 'ram':[], 'disk':[], 'disk_template':[] };
792

    
793
            _.each(flavors, _.bind(function(flv){
794
                this.add_flavor(flv);
795
            }, this));
796
            
797
            this.sort_flavors(this.disks);
798
            this.sort_flavors(this.cpus);
799
            this.sort_flavors(this.mems);
800
            this.sort_flavors(this.disk_templates);
801

    
802
            var self = this;
803
            this.$(".flavor-options li.option").click(function(){
804
                var el = $(this);
805

    
806
                if (el.hasClass("disabled")) { return }
807

    
808
                el.parent().find(".option").removeClass("selected");
809
                el.addClass("selected");
810

    
811
                if (el.hasClass("mem")) { self.last_choice = ["ram", $(this).data("value")] }
812
                if (el.hasClass("cpu")) { self.last_choice = ["cpu", $(this).data("value")] }
813
                if (el.hasClass("disk")) { self.last_choice = ["disk", $(this).data("value")] }
814
                if (el.hasClass("disk_template")) { self.last_choice = ["disk_template", $(this).data("value")] }
815

    
816
                self.update_selected_from_ui();
817
            });
818

    
819
            $(".flavor-opts-list").each(function(){
820
              var el = $(this);
821
              if (el.find(".option").length > 6) {
822
                el.addClass("compact");
823
              }
824
            });
825
        },
826

    
827
        sort_flavors: function(els) {
828
            var prev = undefined;
829
            els.find("li").each(function(i,el){
830
                el = $(el);
831
                if (!prev) { prev = el; return true };
832
                if (el.data("value") < prev.data("value")) {
833
                    prev.before(el);
834
                }
835
                prev = el;
836
            })
837
        },
838
        
839
        ui_selected: function() {
840
            var args = [this.$(".option.cpu.selected").data("value"), 
841
                this.$(".option.mem.selected").data("value"), 
842
                this.$(".option.disk.selected").data("value"),
843
                this.$(".option.disk_template.selected").data("value"),
844
            this.flavors];
845
            
846
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
847
            return flv;
848
        },
849

    
850
        update_selected_flavor: function() {
851
            var flv = this.current_flavor;
852
            if (!flv) { return }
853
            this.$(".option").removeClass("selected");
854

    
855
            this.$(".option.cpu.value-" + flv.get("cpu")).addClass("selected");
856
            this.$(".option.mem.value-" + flv.get("ram")).addClass("selected");
857
            this.$(".option.disk.value-" + flv.get("disk")).addClass("selected");
858
            this.$(".option.disk_template.value-" + flv.get("disk_template")).addClass("selected");
859
            
860
            var disk_el = this.$(".option.disk_template.value-" + flv.get("disk_template"));
861
            var basebgpos = 470;
862
                
863
            var append_to_bg_pos = 40 + (disk_el.index() * 91);
864
            var bg_pos = basebgpos - append_to_bg_pos;
865

    
866
            this.$(".disk-template-description").css({backgroundPosition:'-' + bg_pos + 'px top'})
867
            this.$(".disk-template-description p").html(flv.get_disk_template_info().description || "");
868
        },
869
        
870
        __added_flavors: {'cpu':[], 'ram':[], 'disk':[], 'disk_template':[]},
871
        add_flavor: function(flv) {
872
            var values = {'cpu': flv.get('cpu'), 
873
                          'mem': flv.get('ram'), 
874
                          'disk': flv.get('disk'), 
875
                          'disk_template': flv.get('disk_template')};
876

    
877
            disabled = "";
878
            
879
            if (this.__added_flavors.cpu.indexOf(values.cpu) == -1) {
880
                var cpu = $(('<li class="option cpu value-{0} {1}">' + 
881
                             '<span class="value">{0}</span>' + 
882
                             '<span class="metric">x</span></li>').format(
883
                            _.escape(values.cpu), disabled)).data('value', values.cpu);
884
                this.cpus.append(cpu);
885
                this.__added_flavors.cpu.push(values.cpu);
886
            }
887

    
888
            if (this.__added_flavors.ram.indexOf(values.mem) == -1) {
889
                var mem_value = parseInt(_.escape(values.mem))*1024*1024;
890
                var displayvalue = synnefo.util.readablizeBytes(mem_value, 
891
                                                               0).split(" ");
892
                var mem = $(('<li class="option mem value-{2}">' + 
893
                             '<span class="value">{0}</span>' + 
894
                             '<span class="metric">{1}</span></li>').format(
895
                          displayvalue[0], displayvalue[1], values.mem)).data(
896
                          'value', values.mem);
897
                this.mems.append(mem);
898
                this.__added_flavors.ram.push(values.mem);
899
            }
900

    
901
            if (this.__added_flavors.disk.indexOf(values.disk) == -1) {
902
                var disk = $(('<li class="option disk value-{0}">' + 
903
                              '<span class="value">{0}</span>' + 
904
                              '<span class="metric">GB</span></li>').format(
905
                            _.escape(values.disk))).data('value', values.disk);
906
                this.disks.append(disk);
907
                this.__added_flavors.disk.push(values.disk)
908
            }
909
            
910
            if (this.__added_flavors.disk_template.indexOf(values.disk_template) == -1) {
911
                var template_info = flv.get_disk_template_info();
912
                var disk_template = $(('<li title="{2}" class="option disk_template value-{0}">' + 
913
                                       '<span class="value name">{1}</span>' +
914
                                       '</li>').format(values.disk_template, 
915
                                            _.escape(template_info.name), 
916
                                            template_info.description)).data('value', 
917
                                                                values.disk_template);
918

    
919
                this.disk_templates.append(disk_template);
920
                //disk_template.tooltip({position:'top center', offset:[-5,0], delay:100, tipClass:'tooltip disktip'});
921
                this.__added_flavors.disk_template.push(values.disk_template)
922
            }
923
            
924
        },
925
        
926
        get_active_flavors: function() {
927
            return storage.flavors.active();
928
        },
929

    
930
        get_valid_flavors: function() {
931
            return this.flavors;
932
        },
933

    
934
        update_layout: function() {
935
            this.update_selected_flavor();
936
            this.update_disabled_flavors();
937
            this.validate();
938
            this.validate_selected_flavor();
939
            this.update_quota_display();
940
        },
941
        
942
        update_quota_display: function() {
943

    
944
          var quotas = synnefo.storage.quotas;
945
          _.each(["disk", "ram", "cpu"], function(type) {
946
            var available_dsp = quotas.get('cyclades.'+type).get_readable('available');
947
            var available = quotas.get('cyclades.'+type).get('available');
948
            var content = "({0} left)".format(available_dsp);
949
            if (available <= 0) { content = "(None left)" }
950
            
951
            if (type == "ram") { type = "mem" }
952
            $(".flavor-options."+type+" h4 .available").text(content);
953
            if (available <= 0) {
954
              $(".flavor-options."+type+" h4 .available").addClass("error");
955
            } else {
956
              $(".flavor-options."+type+" h4 .available").removeClass("error");
957
            }
958
          })
959
        },
960

    
961
        reset: function() {
962
            this.current_image = storage.images.at(0);
963
            this.flavors = [];
964
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
965
            this.update_flavors_data();
966
        },
967

    
968
        validate: function() {
969
            if (!this.current_flavor) {
970
                this.parent.$(".form-action.next").hide();
971
            } else {
972
                this.parent.$(".form-action.next").show();
973
            }
974
        },
975

    
976
        get: function() {
977
            return {'flavor': this.current_flavor}
978
        }
979

    
980
    });
981

    
982
    views.CreatePersonalizeView = views.CreateVMStepView.extend({
983
        step: 3,
984
        initialize: function() {
985
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
986
            this.roles = this.$("li.predefined-meta.role .values");
987
            this.name = this.$("input.rename-field");
988
            this.name_changed = false;
989
            this.init_suggested_roles();
990
            this.init_handlers();
991
            this.ssh_list = this.$(".ssh ul");
992
            this.selected_keys = [];
993

    
994
            var self = this;
995
            this.$(".create-ssh-key").click(function() {
996
                var confirm_close = true;
997
                if (confirm_close) {
998
                    snf.ui.main.public_keys_view.show(self.parent);
999
                } else {
1000
                }
1001
            });
1002
        },
1003

    
1004
        init_suggested_roles: function() {
1005
            var cont = this.roles;
1006
            cont.empty();
1007
            
1008
            // TODO: get suggested from snf.api.conf
1009
            _.each(window.SUGGESTED_ROLES, function(r){
1010
                var el = $('<span class="val">{0}</span>'.format(_.escape(r)));
1011
                el.data("value", r);
1012
                cont.append(el);
1013
                el.click(function() {
1014
                    $(this).parent().find(".val").removeClass("selected");
1015
                    $(this).toggleClass("selected");
1016
                })
1017
            });
1018
            
1019
            var self = this;
1020
            $(".ssh li.ssh-key-option").live("click", function(e) {
1021
                var key = $(this).data("model");
1022
                self.select_key(key);
1023
            });
1024
        },
1025

    
1026
        select_key: function(key) {
1027
            var exists = this.selected_keys.indexOf(key.id);
1028
            if (exists > -1) {
1029
                this.selected_keys.splice(exists, 1);
1030
            } else {
1031
                this.selected_keys.push(key.id);
1032
            }
1033
            this.update_ui_keys_selections(this.selected_keys);
1034
        },
1035

    
1036
        update_ui_keys_selections: function(keys) {
1037
            var self = this;
1038
            self.$(".ssh-key-option").removeClass("selected");
1039
            self.$(".ssh-key-option .check").attr("checked", false);
1040
            _.each(keys, function(kid) {
1041
                $("#ssh-key-option-" + kid).addClass("selected");
1042
                $("#ssh-key-option-" + kid).find(".check").attr("checked", true);
1043
            });
1044
        },
1045

    
1046
        update_ssh_keys: function() {
1047
            this.ssh_list.empty();
1048
            var keys = snf.storage.keys.models;
1049
            if (keys.length == 0) { 
1050
                this.$(".ssh .empty").show();
1051
            } else {
1052
                this.$(".ssh .empty").hide();
1053
            }
1054
            _.each(keys, _.bind(function(key){
1055
                var el = $('<li id="ssh-key-option-{1}" class="ssh-key-option">{0}</li>'.format(_.escape(key.get("name")), key.id));
1056
                var check = $('<input class="check" type="checkbox"></input>')
1057
                el.append(check);
1058
                el.data("model", key);
1059
                this.ssh_list.append(el);
1060
            }, this));
1061
        },
1062

    
1063
        init_handlers: function() {
1064
            this.name.bind("keypress", _.bind(function(e) {
1065
                this.name_changed = true;
1066
                if (e.keyCode == 13) { this.parent.set_step(4); this.parent.update_layout() };    
1067
            }, this));
1068

    
1069
            this.name.bind("click", _.bind(function() {
1070
                if (!this.name_changed) {
1071
                    this.name.val("");
1072
                }
1073
            }, this))
1074
        },
1075

    
1076
        show: function() {
1077
            views.CreatePersonalizeView.__super__.show.apply(this, arguments);
1078
            this.update_layout();
1079
        },
1080
        
1081
        update_layout: function() {
1082
            var params = this.parent.get_params();
1083

    
1084
            if (!params.image || !params.flavor) { return }
1085

    
1086
            if (!params.image) { return }
1087
            var vm_name_tpl = snf.config.vm_name_template || "My {0} server";
1088
            var vm_name = vm_name_tpl.format(_.escape(params.image.get("name")));
1089
            var orig_name = vm_name;
1090
            
1091
            var existing = true;
1092
            var j = 0;
1093

    
1094
            while (existing && !this.name_changed) {
1095
                var existing = storage.vms.select(function(vm){return vm.get("name") == vm_name}).length
1096
                if (existing) {
1097
                    j++;
1098
                    vm_name = orig_name + " " + j;
1099
                }
1100
            }
1101

    
1102
            if (!_(this.name.val()).trim() || !this.name_changed) {
1103
                this.name.val(vm_name);
1104
            }
1105

    
1106
            if (!this.name_changed && this.parent.visible()) {
1107
                if (!$.browser.msie && !$.browser.opera) {
1108
                    this.$("#create-vm-name").select();
1109
                } else {
1110
                    window.setTimeout(_.bind(function(){
1111
                        this.$("#create-vm-name").select();
1112
                    }, this), 400)
1113
                }
1114
            }
1115
            
1116
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
1117
            this.name.css({backgroundImage:"url({0})".format(img)})
1118
            
1119
            if (!params.image.supports('ssh')) {
1120
                this.disable_ssh_keys();
1121
            } else {
1122
                this.enable_ssh_keys();
1123
                this.update_ssh_keys();
1124
            }
1125

    
1126
            this.update_ui_keys_selections(this.selected_keys);
1127
        },
1128

    
1129
        disable_ssh_keys: function() {
1130
            this.$(".disabled.desc").show();
1131
            this.$(".empty.desc").hide();
1132
            this.$(".ssh .confirm-params").hide();
1133
            this.selected_keys = [];
1134
        },
1135

    
1136
        enable_ssh_keys: function() {
1137
            this.$(".ssh .confirm-params").show();
1138
            this.$(".disabled.desc").hide();
1139
        },
1140

    
1141
        reset: function() {
1142
            this.roles.find(".val").removeClass("selected");
1143
            this.name_changed = false;
1144
            this.selected_keys = [];
1145
            this.update_layout();
1146
        },
1147

    
1148
        get_meta: function() {
1149
            if (this.roles.find(".selected").length == 0) {
1150
                return false;
1151
            }
1152

    
1153
            var role = $(this.roles.find(".selected").get(0)).data("value");
1154
            return {'Role': role }
1155
        },
1156

    
1157
        get: function() {
1158
            var val = {'name': this.name.val() };
1159
            if (this.get_meta()) {
1160
                val.metadata = this.get_meta();
1161
            }
1162

    
1163
            val.keys = _.map(this.selected_keys, function(k){ return snf.storage.keys.get(k)});
1164
            
1165
            return val;
1166
        }
1167
    });
1168

    
1169
    views.CreateSubmitView = views.CreateVMStepView.extend({
1170
        step: 4,
1171
        initialize: function() {
1172
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
1173
            this.roles = this.$("li.predefined-meta.role .values");
1174
            this.confirm = this.$(".confirm-params ul");
1175
            this.name = this.$("h3.vm-name");
1176
            this.keys = this.$(".confirm-params.ssh");
1177
            this.meta = this.$(".confirm-params.meta");
1178
            this.init_handlers();
1179
        },
1180

    
1181
        init_handlers: function() {
1182
        },
1183

    
1184
        show: function() {
1185
            views.CreateSubmitView.__super__.show.apply(this, arguments);
1186
            this.update_layout();
1187
        },
1188
        
1189
        update_flavor_details: function() {
1190
            var flavor = this.parent.get_params().flavor;
1191

    
1192
            function set_detail(sel, key) {
1193
                var val = key;
1194
                if (key == undefined) { val = flavor.get(sel) };
1195
                this.$(".confirm-cont.flavor .flavor-" + sel + " .value").text(val)
1196
            }
1197
            
1198
            set_detail("cpu", flavor.get("cpu") + "x");
1199
            set_detail("ram", flavor.get("ram") + " MB");
1200
            set_detail("disk", util.readablizeBytes(flavor.get("disk") * 1024 * 1024 * 1024));
1201
            set_detail("disktype", flavor.get_disk_template_info().name);
1202
        },
1203

    
1204
        update_image_details: function() {
1205
            var image = this.parent.get_params().image;
1206

    
1207
            function set_detail(sel, key) {
1208
                var val = key;
1209
                if (key == undefined) { val = image.get(sel) };
1210
                this.$(".confirm-cont.image .image-" + sel + " .value").text(val)
1211
            }
1212
            
1213
            set_detail("description", image.get_description());
1214
            set_detail("name");
1215
            set_detail("os", _(image.get_os()).capitalize());
1216
            set_detail("gui", image.get_gui());
1217
            set_detail("size", _.escape(image.get_readable_size()));
1218
            set_detail("kernel");
1219
        },
1220

    
1221
        update_selected_keys: function(keys) {
1222
            this.keys.empty();
1223
            if (!keys || keys.length == 0) {
1224
                this.keys.append(this.make("li", {'class':'empty'}, 'No keys selected'))
1225
            }
1226
            _.each(keys, _.bind(function(key) {
1227
                var el = this.make("li", {'class':'selected-ssh-key'}, key.get('name'));
1228
                this.keys.append(el);
1229
            }, this))
1230
        },
1231

    
1232
        update_selected_meta: function(meta) {
1233
            this.meta.empty();
1234
            if (!meta || meta.length == 0) {
1235
                this.meta.append(this.make("li", {'class':'empty'}, 'No tags selected'))
1236
            }
1237
            _.each(meta, _.bind(function(value, key) {
1238
                var el = this.make("li", {'class':"confirm-value"});
1239
                var name = this.make("span", {'class':"ckey"}, key);
1240
                var value = this.make("span", {'class':"cval"}, value);
1241

    
1242
                $(el).append(name)
1243
                $(el).append(value);
1244
                this.meta.append(el);
1245
            }, this));
1246
        },
1247

    
1248
        update_layout: function() {
1249
            var params = this.parent.get_params();
1250
            if (!params.image || !params.flavor) { return }
1251

    
1252
            if (!params.image) { return }
1253

    
1254
            this.name.text(params.name);
1255

    
1256
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
1257
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
1258
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
1259
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
1260

    
1261
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
1262
            this.name.css({backgroundImage:"url({0})".format(img)})
1263

    
1264
            this.update_image_details();
1265
            this.update_flavor_details();
1266

    
1267
            if (!params.image.supports('ssh')) {
1268
                this.keys.hide();
1269
                this.keys.prev().hide();
1270
            } else {
1271
                this.keys.show();
1272
                this.keys.prev().show();
1273
                this.update_selected_keys(params.keys);
1274
            }
1275
            
1276
            this.update_selected_meta(params.metadata);
1277
        },
1278

    
1279
        reset: function() {
1280
            this.update_layout();
1281
        },
1282

    
1283
        get_meta: function() {
1284
        },
1285

    
1286
        get: function() {
1287
            return {};
1288
        }
1289
    });
1290

    
1291
    views.CreateVMView = views.Overlay.extend({
1292
        
1293
        view_id: "create_vm_view",
1294
        content_selector: "#createvm-overlay-content",
1295
        css_class: 'overlay-createvm overlay-info',
1296
        overlay_id: "metadata-overlay",
1297

    
1298
        subtitle: false,
1299
        title: "Create new machine",
1300

    
1301
        initialize: function(options) {
1302
            views.CreateVMView.__super__.initialize.apply(this);
1303
            this.current_step = 1;
1304

    
1305
            this.password_view = new views.VMCreationPasswordView();
1306

    
1307
            this.steps = [];
1308
            this.steps[1] = new views.CreateImageSelectView(this);
1309
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
1310

    
1311
            this.steps[2] = new views.CreateFlavorSelectView(this);
1312
            this.steps[3] = new views.CreatePersonalizeView(this);
1313
            this.steps[4] = new views.CreateSubmitView(this);
1314

    
1315
            this.cancel_btn = this.$(".create-controls .cancel");
1316
            this.next_btn = this.$(".create-controls .next");
1317
            this.prev_btn = this.$(".create-controls .prev");
1318
            this.submit_btn = this.$(".create-controls .submit");
1319

    
1320
            this.history = this.$(".steps-history");
1321
            this.history_steps = this.$(".steps-history .steps-history-step");
1322
            
1323
            this.init_handlers();
1324
        },
1325

    
1326
        init_handlers: function() {
1327
            var self = this;
1328
            this.next_btn.click(_.bind(function(){
1329
                this.set_step(this.current_step + 1);
1330
                this.update_layout();
1331
            }, this))
1332
            this.prev_btn.click(_.bind(function(){
1333
                this.set_step(this.current_step - 1);
1334
                this.update_layout();
1335
            }, this))
1336
            this.cancel_btn.click(_.bind(function(){
1337
                this.close_all();
1338
            }, this))
1339
            this.submit_btn.click(_.bind(function(){
1340
                this.submit();
1341
            }, this))
1342
            
1343
            this.history.find(".completed").live("click", function() {
1344
                var step = parseInt($(this).attr("id").replace("vm-create-step-history-", ""));
1345
                self.set_step(step);
1346
                self.update_layout();
1347
            })
1348
        },
1349

    
1350
        set_step: function(st) {
1351
        },
1352
        
1353
        validate: function(data) {
1354
            if (_(data.name).trim() == "") {
1355
                this.$(".form-field").addClass("error");
1356
                return false;
1357
            } else {
1358
                return true;
1359
            }
1360
        },
1361

    
1362
        submit: function() {
1363
            if (this.submiting) { return };
1364
            var data = this.get_params();
1365
            var meta = {};
1366
            var extra = {};
1367
            var personality = [];
1368

    
1369
            if (this.validate(data)) {
1370
                this.submit_btn.addClass("in-progress");
1371
                this.submiting = true;
1372
                if (data.metadata) { meta = data.metadata; }
1373
                if (data.keys && data.keys.length > 0) {
1374
                    personality.push(data.image.personality_data_for_keys(data.keys))
1375
                }
1376

    
1377
                if (personality.length) {
1378
                    extra['personality'] = _.flatten(personality);
1379
                }
1380

    
1381
                storage.vms.create(data.name, data.image, data.flavor, meta, extra, _.bind(function(data){
1382
                    this.close_all();
1383
                    this.password_view.show(data.server.adminPass, data.server.id);
1384
                    this.submiting = false;
1385
                }, this));
1386
            }
1387
        },
1388

    
1389
        close_all: function() {
1390
            this.hide();
1391
        },
1392

    
1393
        reset: function() {
1394
            this.current_step = 1;
1395

    
1396
            this.steps[1].reset();
1397
            this.steps[2].reset();
1398
            this.steps[3].reset();
1399
            this.steps[4].reset();
1400

    
1401
            this.steps[1].show();
1402
            this.steps[2].show();
1403
            this.steps[3].show();
1404
            this.steps[4].show();
1405

    
1406
            this.submit_btn.removeClass("in-progress");
1407
        },
1408

    
1409
        onShow: function() {
1410
        },
1411

    
1412
        update_layout: function() {
1413
            this.show_step(this.current_step);
1414
            this.current_view.update_layout();
1415
        },
1416

    
1417
        beforeOpen: function() {
1418
            if (!this.skip_reset_on_next_open) {
1419
                this.submiting = false;
1420
                this.reset();
1421
                this.current_step = 1;
1422
                this.$(".steps-container").css({"margin-left":0 + "px"});
1423
                this.show_step(1);
1424
            }
1425
            
1426
            this.skip_reset_on_next_open = false;
1427
            this.update_layout();
1428
        },
1429
        
1430
        set_step: function(step) {
1431
            if (step <= 1) {
1432
                step = 1
1433
            }
1434
            if (step > this.steps.length - 1) {
1435
                step = this.steps.length - 1;
1436
            }
1437
            this.current_step = step;
1438
        },
1439

    
1440
        show_step: function(step) {
1441
            // FIXME: this shouldn't be here
1442
            // but since we are not calling step.hide this should work
1443
            this.steps[1].image_details.hide();
1444

    
1445
            this.current_view = this.steps[step];
1446
            this.update_controls();
1447

    
1448
            this.steps[step].show();
1449
            var width = this.el.find('.container').width();
1450
            var left = (step -1) * width * -1;
1451
            this.$(".steps-container").animate({"margin-left": left + "px"}, 300);
1452

    
1453
            this.update_steps_history();
1454
        },
1455

    
1456
        update_steps_history: function() {
1457
            var self = this;
1458
            function get_step(s) {
1459
                return self.history.find(".step" + s + "h");
1460
            }
1461
            
1462
            var current_step = parseInt(this.current_view.step);
1463
            _.each(this.steps, function(stepv) {
1464
                var step = parseInt(stepv.step);
1465
                get_step(step).removeClass("completed").removeClass("current");
1466
                if (step == current_step) {
1467
                    get_step(step).removeClass("completed").addClass("current");
1468
                }
1469
                if (step < current_step) {
1470
                    get_step(step).removeClass("current").addClass("completed");
1471
                }
1472
            });
1473
        },
1474

    
1475
        update_controls: function() {
1476
            var step = this.current_step;
1477
            if (step == 1) {
1478
                this.prev_btn.hide();
1479
                this.cancel_btn.show();
1480
            } else {
1481
                this.prev_btn.show();
1482
                this.cancel_btn.hide();
1483
            }
1484
            
1485
            if (step == this.steps.length - 1) {
1486
                this.next_btn.hide();
1487
                this.submit_btn.show();
1488
            } else {
1489
                this.next_btn.show();
1490
                this.submit_btn.hide();
1491
            }
1492
        },
1493

    
1494
        get_params: function() {
1495
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
1496
        }
1497
    });
1498
    
1499
})(this);
1500