Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_networks_view.js @ 40e5d2d2

History | View | Annotate | Download (44.8 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 || {};
46
    var views = snf.views = snf.views || {}
47

    
48
    // shortcuts
49
    var bb = root.Backbone;
50
    
51
    // logging
52
    var logger = new snf.logging.logger("SNF-VIEWS");
53
    var debug = _.bind(logger.debug, logger);
54
    
55
    
56
    views.NetworkConnectVMsOverlay = views.Overlay.extend({
57
        title: "Connect machine",
58
        overlay_id: "overlay-select-vms",
59
        content_selector: "#network-vms-select-content",
60
        css_class: "overlay-info",
61

    
62
        initialize: function() {
63
            views.NetworkConnectVMsOverlay.__super__.initialize.apply(this);
64
            this.list = this.$(".vms-list ul");
65
            this.empty_message = this.$(".empty-message");
66

    
67
            // flag for submit handler to avoid duplicate bindings
68
            this.submit_handler_set = false;
69
        },
70
        
71
        init_handlers: function() {
72
            var self = this;
73
            this.list.find("li").click(function(){
74
                $(this).toggleClass("selected");
75
            });
76
            
77
            if (!this.submit_handler_set) {
78
                // avoid duplicate submits
79
                this.el.find(".create").click(_.bind(function() {
80
                    this.submit();
81
                }, this));
82
                this.submit_handler_set = true;
83
            }
84
        },
85

    
86
        reset: function() {
87
            this.list.find("li").remove();
88
        },
89

    
90
        beforeOpen: function() {
91
            this.reset();
92
            this.update_layout();
93
        },
94
        
95
        vm: function(vm) {
96
            if (vm.id) { var id = vm.id } else {var id = vm}
97
            return this.list.find(".vm-" + id);
98
        },
99

    
100
        get_selected: function() {
101
            return this.list.find(".selected").map(function() {return $(this).data('vm')})
102
        },
103

    
104
        update_layout: function() {
105
            if (this.vms.length == 0) {
106
                this.empty_message.show();
107
            } else {
108
                this.empty_message.hide();
109
            }
110

    
111
            _.each(this.vms, _.bind(function(vm){
112
                
113
                var html = '<li class="vm option options-object vm-{0}">' +
114
                           '<div class="options-object-cont">' +
115
                           '{2}' + 
116
                           '<span class="title">{1}</span>' + 
117
                           '<span class="value">{3}</span></div>' + 
118
                           '</li>';
119
                var el = $(html.format(vm.id, 
120
                                       util.truncate(_.escape(vm.get("name")), 23), 
121
                                       snf.ui.helpers.vm_icon_tag(vm, "small", {'class':'os'}),
122
                                       _.escape(vm.get_os())
123
                                      ))
124
                el.data({vm:vm, vm_id:vm.id})
125
                this.list.append(el);
126

    
127
                vm.bind("remove", function(){ el.remove()})
128
                vm.bind("change:name", function(i,v){el.find(".title").text(v)})
129
            }, this));
130
            
131
            this.init_handlers();
132
            this.set_selected();
133
        },
134

    
135
        set_selected: function() {
136
            _.each(this.selected, _.bind(function(el){
137
                this.vm(el).addClass("selected");
138
            }, this));
139
        },
140

    
141
        show_vms: function(network, vms, selected, callback) {
142
            this.network = network;
143
            this.reset();
144
            this.set_subtitle(network.escape("name"));
145
            this.vms = vms;
146
            if (!synnefo.config.network_allow_duplicate_vm_nics) {
147
                this.vms = _.filter(this.vms, function(vm) {
148
                    return !vm.connected_to(this.network);
149
                }, this);
150
            }
151

    
152
            this.selected = selected;
153
            this.cb = callback;
154
            this.show();
155
        },
156

    
157
        submit: function() {
158
            this.cb(this.get_selected());
159
        }
160
    })
161

    
162
    views.NetworkActionsView = views.View.extend({
163
        
164
        initialize: function(view, net, el, opts) {
165
            this.parent = view
166
            this.network = net;
167
            this.el = el;
168
            
169
            this.actions = this.$(".actions");
170
            this.selected = undefined;
171

    
172
            this.destroy = this.$(".actions .destroy a");
173
            this.connect = this.$(".actions .add");
174

    
175
            this.init_handlers();
176
            this.update_layout();
177
        },
178

    
179
        init_handlers: function() {
180
            this.connect.click(_.bind(function(e){
181
                e.preventDefault();
182
            }))
183
        },
184

    
185
        update_layout: function() {
186
        }
187
    });
188

    
189
    views.NetworkCreateView = views.Overlay.extend({
190
        view_id: "network_create_view",
191
        content_selector: "#networks-create-content",
192
        css_class: 'overlay-networks-create overlay-info',
193
        overlay_id: "network-create-overlay",
194

    
195
        title: "Create new private network",
196
        subtitle: "Networks",
197

    
198
        initialize: function(options) {
199
            views.NetworkCreateView.__super__.initialize.apply(this);
200

    
201
            this.create_button = this.$("form .form-action.create");
202
            this.text = this.$(".network-create-name");
203
            this.form = this.$("form");
204

    
205
            this.dhcp_select = this.$("#network-create-dhcp");
206
            this.type_select = this.$("#network-create-type");
207
            this.subnet_select = this.$("#network-create-subnet");
208
            this.subnet_custom = this.$("#network-create-subnet-custom");
209
                
210
            this.dhcp_form = this.$("#network-create-dhcp-fields");
211
            
212
            this.subnet_select.find(".subnet").remove();
213
            _.each(synnefo.config.network_suggested_subnets, function(subnet){
214
                this.subnet_select.append($('<option value='+subnet+' class="subnet">'+subnet+'</option>'));
215
            }, this);
216

    
217
            this.type_select.find(".subnet").remove();
218
            _.each(synnefo.config.network_available_types, function(name, value){
219
                this.type_select.append($('<option value='+value+' class="subnet">'+name+'</option>'));
220
            }, this);
221
            
222
            this.disable_network_type = false;
223
            if (_.keys(synnefo.config.network_available_types).length <= 1) {
224
                this.disable_network_type = true;
225
                this.type_select.closest(".form-field").hide();
226
            }
227

    
228
            this.check_dhcp_form();
229
            this.init_handlers();
230
        },
231

    
232
        reset_dhcp_form: function() {
233
          this.subnet_select.find("option")[0].selected = 1;
234
          this.subnet_custom.val("");
235
        },
236

    
237
        check_dhcp_form: function() {
238
            if (this.dhcp_select.is(":checked")) {
239
                this.dhcp_form.show();
240
            } else {
241
                this.dhcp_form.hide();
242
            }
243
            
244
            if (this.subnet_select.val() == "custom") {
245
                this.subnet_custom.show();
246
            } else {
247
                this.subnet_custom.hide();
248
            }
249
        },
250

    
251
        init_handlers: function() {
252

    
253
            this.dhcp_select.click(_.bind(function(e){
254
                this.check_dhcp_form();
255
                this.reset_dhcp_form();
256
            }, this));
257

    
258
            this.subnet_select.change(_.bind(function(e){
259
                this.check_dhcp_form();
260
                if (this.subnet_custom.is(":visible")) {
261
                    this.subnet_custom.focus();
262
                }
263
            }, this));
264

    
265
            this.create_button.click(_.bind(function(e){
266
                this.submit();
267
            }, this));
268

    
269
            this.form.submit(_.bind(function(e){
270
                e.preventDefault();
271
                this.submit;
272
                return false;
273
            }, this))
274

    
275
            this.text.keypress(_.bind(function(e){
276
                if (e.which == 13) {this.submit()};
277
            },this))
278
        },
279

    
280
        submit: function() {
281
            if (this.validate()) {
282
                this.create();
283
            };
284
        },
285
        
286
        validate: function() {
287
            // sanitazie
288
            var t = this.text.val();
289
            t = t.replace(/^\s+|\s+$/g,"");
290
            this.text.val(t);
291

    
292
            if (this.text.val() == "") {
293
                this.text.closest(".form-field").addClass("error");
294
                this.text.focus();
295
                return false;
296
            } else {
297
                this.text.closest(".form-field").removeClass("error");
298
            }
299
            
300
            if (this.dhcp_select.is(":checked")) {
301
                if (this.subnet_select.val() == "custom") {
302
                    var sub = this.subnet_custom.val();
303
                    sub = sub.replace(/^\s+|\s+$/g,"");
304
                    this.subnet_custom.val(sub);
305
                        
306
                    if (!synnefo.util.IP_REGEX.exec(this.subnet_custom.val())) {
307
                        this.subnet_custom.closest(".form-field").prev().addClass("error");
308
                        return false;
309
                    } else {
310
                        this.subnet_custom.closest(".form-field").prev().removeClass("error");
311
                    }
312
                };
313
            }
314

    
315
            return true;
316
        },
317

    
318
        create: function() {
319
            this.create_button.addClass("in-progress");
320

    
321
            var name = this.text.val();
322
            var dhcp = this.dhcp_select.is(":checked");
323
            var subnet = null;
324
            var type = this.type_select.val();
325

    
326
            if (this.disable_network_type) { type = null };
327

    
328
            if (dhcp) {
329
                if (this.subnet_select.val() == "custom") {
330
                    subnet = this.subnet_custom.val();
331
                } else if (this.subnet_select.val() == "auto") {
332
                    subnet = null;
333
                } else {
334
                    subnet = this.subnet_select.val();
335
                }
336
                
337
            }
338

    
339
            snf.storage.networks.create(name, type, subnet, dhcp, _.bind(function(){
340
                this.hide();
341
            }, this));
342
        },
343

    
344
        beforeOpen: function() {
345
            this.create_button.removeClass("in-progress")
346
            this.text.closest(".form-field").removeClass("error");
347
            this.text.val("");
348
            this.text.show();
349
            this.text.focus();
350
            this.subnet_custom.val("");
351
            this.subnet_select.val("auto");
352
            this.dhcp_select.attr("checked", true);
353
            this.type_select.val(_.keys(synnefo.config.network_available_types)[0]);
354
            this.check_dhcp_form();
355
        },
356

    
357
        onOpen: function() {
358
            this.text.focus();
359
        }
360
    });
361

    
362
    views.NetworkNICView = views.View.extend({
363

    
364
        initialize: function(nic, parent, firewall_controls, el) {
365
            this.firewall_controls = firewall_controls || false;
366
            this.nic = nic;
367
            this.vm = nic.get_vm();
368
            // parent view di
369
            this.parent = parent;
370
            // TODO make it better
371
            this.el = el || this.parent.get_nic_view(nic);
372

    
373
            this.init_layout();
374
            this.update_layout();
375

    
376
            this.disconnect = this.$(".action-disconnect");
377
            this.confirm_el = this.$(".confirm_single");
378
            this.cancel = this.$("button.no");
379
            this.confirm = this.$("button.yes");
380
            this.details = this.$(".action-details");
381
            this.vm_connect = this.$(".machine-connect");
382

    
383
            this.init_handlers();
384
            this.connect_overlay = new views.VMConnectView();
385
            
386
            this.firewall_view = undefined;
387
            if (this.firewall_controls) {
388
                this.firewall_view = new views.FirewallEditView(this.nic, this.parent.network, this);
389
            }
390

    
391
        },
392
        
393
        reset_all_net_actions: function(act_types) {
394
            synnefo.storage.networks.each(function(n){
395
                var actions = n.get('actions');
396
                _.each(act_types, function(type){
397
                    actions.remove_all(type);
398
                })
399
            })
400
        },
401

    
402
        init_handlers: function() {
403
            if (!this.parent.network.is_public()) {
404
                this.disconnect.click(_.bind(function(e){
405
                    e.preventDefault();
406
                    this.reset_all_net_actions(['destroy','disconnect']);
407
                    this.parent.network.get("actions").remove_all("disconnect");
408
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
409
                    this.parent.network.get("actions").remove("destroy");
410
                }, this));
411
                this.cancel.click(_.bind(function(e){
412
                    this.parent.network.get("actions").remove("disconnect", this.nic.id);
413
                    e.preventDefault()
414
                }, this));
415

    
416
                this.confirm.click(_.bind(function(e){
417
                    e.preventDefault()
418
                    this.disconnect_nic();
419
                    this.confirm_el.hide();
420
                    this.disconnect.removeClass("selected");
421
                }, this));
422

    
423
                snf.ui.main.bind("view:change", _.bind(function(v) {
424
                    if (v == "networks" ){ return }
425
                    this.confirm_el.hide();
426
                    this.disconnect.removeClass("selected");
427
                }, this));
428

    
429
                this.$(".remove-icon").click(_.bind(function(){
430
                    this.reset_all_net_actions(['destroy','disconnect']);
431
                    this.parent.network.get("actions").remove_all("disconnect");
432
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
433
                    this.parent.network.get("actions").remove("destroy");
434
                }, this));
435

    
436
                this.vm_connect.click(_.bind(function() {
437
                    this.connect_overlay.show(this.vm);
438
                }, this));
439
                
440
                this.parent.network.bind("change:actions", _.bind(function(model, action){
441
                    if (this.parent.network.get("actions").contains("disconnect", this.nic.id)) {
442
                        this.confirm_disconnect();
443
                    } else {
444
                        this.cancel_disconnect();
445
                    }
446
                }, this));
447
            }
448
            
449
            var vm = this.vm;
450
            this.details.click(function(e){
451
                e.preventDefault();
452
                snf.ui.main.show_vm_details(vm);
453
            });
454

    
455
        },
456

    
457
        cancel_disconnect: function() {
458
            this.confirm_el.hide();
459
            this.disconnect.removeClass("selected");
460
            this.$(".net-vm-actions a").removeClass("visible");
461
        },
462

    
463
        confirm_disconnect: function() {
464
            this.confirm_el.show();
465
            this.disconnect.addClass("selected");
466
            this.$(".net-vm-actions a").addClass("visible");
467
        },
468

    
469
        init_layout: function() {
470
            if (!this.firewall_controls) { return };
471
        },
472

    
473
        update_layout: function() {
474
            this.$(".vm-name").text(snf.util.truncate(this.vm.get("name"), 40));
475
            this.$("img.logo").attr("src", ui.helpers.vm_icon_path(this.vm, "medium"));
476

    
477
            if (this.firewall_view) {
478
                this.$(".ipv4-text").text(this.nic.get_v4_address());
479
                this.$(".ipv6-text").text(this.nic.get_v6_address());
480
            }
481

    
482
            if (this.firewall_view) {
483
                this.firewall_view.update_layout();
484
            }
485

    
486
            if (!this.firewall_view) {
487
                this.$(".ip4-container").hide();
488
                this.$(".ip6-container").hide();
489
                
490
                if (this.nic.get("ipv4")) {
491
                    this.$(".ipv4-text").text(this.nic.get_v4_address());
492
                    this.$(".ip4-container").show();
493
                    this.$(".machine-connect .content").hide();
494
                } else if (this.nic.get("ipv6")) {
495
                    this.$(".ipv6-text").text(this.nic.get_v6_address());
496
                    this.$(".ip6-container").show();
497
                    this.$(".machine-connect .content").hide();
498
                } else {
499
                    this.$(".machine-connect .content").show();
500
                }
501
            } else {
502
            }
503
        },
504

    
505
        disconnect_nic: function() {
506
            this.$("a.selected").removeClass("selected");
507
            this.nic.get_network().remove_nic(this.nic);
508
        },
509
    })
510

    
511
    views.NetworkModelRenameView = views.View.extend({
512
        initialize: function(parent, network) {
513
            this.parent = parent;
514
            this.network = network;
515
            this.el = this.parent.el.find(".name-div");
516

    
517
            this.icon = this.$(".rename-network");
518
            this.save = this.$("span.save");
519
            this.cancel = this.$("span.cancel");
520
            this.buttons = this.$(".editbuttons");
521
            this.name = this.$("span.name");
522
            this.editing = false;
523
            this.init_handlers();
524
            this.update_layout();
525
        },
526

    
527
        init_handlers: function() {
528
            this.icon.click(_.bind(function(){
529
                this.editing = true;
530
                this.update_layout();
531
            }, this));
532
            this.cancel.click(_.bind(function(){
533
                this.editing = false;
534
                this.update_layout();
535
            }, this));
536
            this.save.click(_.bind(function(){
537
                this.submit();
538
            }, this))
539
        },
540
        
541
        submit: function() {
542
            var value = _(this.input.val()).trim();
543
            if (value == "") { return }
544

    
545
            this.network.rename(value, _.bind(function(){
546
                this.editing = false;
547
                this.update_layout();
548
            }, this));
549
        },
550

    
551
        create_input: function() {
552
            this.input = $('<input type="text" class="network-rename-input" />');
553
            this.input.val(this.network.get("name"));
554
            this.el.append(this.input);
555
            this.input.focus();
556
            this.input.bind("keydown", _.bind(function(ev){
557
                ev.keyCode = ev.keyCode || ev.which;
558
                if (ev.keyCode == 13) { this.submit(); };
559
                if (ev.keyCode == 27) {this.editing = false; this.update_layout()};
560
            }, this));
561
        },
562

    
563
        remove_input: function() {
564
            if (!this.input) { return }
565
            this.input.remove();
566
        },
567

    
568
        update_layout: function() {
569
            if (this.editing) {
570
                if (this.buttons.is(":visible")) { return }
571
                this.icon.hide();
572
                this.buttons.show();
573
                this.create_input();
574
                this.name.hide();
575
            } else {
576
                this.buttons.hide();
577
                this.remove_input();
578
                this.name.show();
579
                this.icon.show();
580
            }
581
        }
582
    })
583

    
584
    views.FirewallEditView = views.View.extend({
585

    
586
        initialize: function(nic, network, parent) {
587
            this.parent = parent;
588
            this.vm = nic.get_vm();
589
            this.nic = nic;
590
            this.network = network;
591
            this.el = this.parent.el;
592

    
593
            views.FirewallEditView.__super__.initialize.apply(this);
594

    
595
            // elements
596
            this.toggler = this.$(".firewall-toggle");
597
            this.indicator = this.$(".machines-label span");
598
            this.progress = this.$(".network-progress-indicator");
599
            this.content = this.$(".firewall-content");
600
            this.inputs = this.$("input[type=radio]");
601
            this.labels = this.$("span.checkbox-legends, label.checkbox-legends");
602
            this.apply = this.$(".firewall-apply");
603

    
604
            this.$(".firewall-content").hide();
605
            this.$(".firewall-content input[type=radio]").attr("name", "firewall-opt-for-{0}".format(this.vm.id))
606
            var mode = this.vm.get_firewall_profile();
607
            this.$(".firewall-content input[value={0}]".format(mode)).attr("checked", true);
608

    
609
            this.init_handlers();
610
            this.update_layout();
611

    
612
            var self = this;
613
            this.nic.bind("change:pending_firewall_sending", function(nic, value) {
614
                if (value) {
615
                    self.apply.addClass("in-progress");       
616
                    self.progress.show();
617
                } else {
618
                    self.apply.removeClass("in-progress");       
619
                    self.progress.hide();
620
                    self.toggler.click();
621
                }
622
            });
623

    
624
            this.nic.bind("change:firewallProfile", function(nic){
625
                self.update_layout();
626
                self.reset_value();
627
            })
628

    
629
        },
630
        
631
        _get_selected: function() {
632
            return this.inputs.filter(":checked");
633
        },
634

    
635
        reset_selected: function() {
636
        },
637

    
638
        submit: function() {
639
        },
640

    
641
        reset_value: function() {
642
            this.inputs.filter("[value={0}]".format(
643
              this.nic.get('firewallProfile'))).attr("checked", true);
644
        },
645

    
646
        init_handlers: function() {
647
            this.toggler.click(_.bind(function(){
648
                cont = this.content;
649
                if (cont.is(":visible")) {
650
                    this.hide_firewall();
651
                    this.reset_value();
652
                } else {
653
                    this.show_firewall();
654
                }
655

    
656
                $(window).trigger("resize");
657
            }, this))
658
            
659
            this.apply.click(_.bind(function(){
660
                this.nic.set_firewall(this.value());
661
            }, this))
662

    
663
            this.inputs.change(_.bind(function(){
664
                this.update_selected();
665
            }, this))
666
            
667
            var self = this;
668
            this.$(".checkbox-legends").click(function(el) {
669
                var el = $(this);
670
                el.prev().click();
671
                self.update_selected();
672
            })
673
        },
674

    
675
        update_selected: function() {
676
            this.update_layout();
677
        },
678

    
679
        show_firewall: function() {
680
            this.content.slideDown(100, function(){$(window).trigger("resize")});
681
            this.toggler.addClass("open");
682
        },
683

    
684
        hide_firewall: function() {
685
            this.content.slideUp(100, function(){$(window).trigger("resize")});
686
            this.toggler.removeClass("open");
687
        },
688

    
689
        value: function() {
690
            return this._get_selected().val();
691
        },
692

    
693
        update_layout: function() {
694
            if (this.value() == this.vm.get_firewall_profile()) {
695
                this.apply.hide();
696
            } else {
697
                this.apply.show();
698
            }
699

    
700
            var profile = this.vm.get_firewall_profile();
701
            if (this.vm.has_firewall(this.network.id)) {
702
                this.$(".firewall-toggle .label span").text("On");
703
                this.$(".firewall-toggle .label span").removeClass("firewall-off");
704
                this.$(".firewall-toggle .label span").addClass("firewall-on");
705
            } else {
706
                this.$(".firewall-toggle .label span").text("Off");
707
                this.$(".firewall-toggle .label span").removeClass("firewall-on");
708
                this.$(".firewall-toggle .label span").addClass("firewall-off");
709
            }
710
            
711
            this.$("span.checkbox-legends").removeClass("current");
712
            this.inputs.filter("[value={0}]".format(profile)).next().addClass("current");
713
            
714
        }
715
    })
716

    
717
    views.NetworkModelView = views.View.extend({
718
        
719
        firewall: false,
720

    
721
        initialize: function(network, view) {
722
            this.parent_view = view;
723
            this.network = network;
724
            this.main_view_id = this.main_view_id ? this.main_view_id : "networks_view_" + network.id;
725
            this.is_public = network.is_public();
726

    
727
            this.init_nics_handlers();
728
            
729
            this.view_id = "networks_view_" + network.id;
730
            views.NetworkModelView.__super__.initialize.call(this);
731

    
732
            this.nics_views = {};
733

    
734
            this.el = this.create_el();
735

    
736
            // element helpers
737
            this.nics_list = this.$(".machines-list");
738
            this.nics_list_toggler = this.$(".list-toggle");
739
            
740
            this.init_handlers();
741
            this.init_toggler_handlers();
742
            this.update_nics();
743
            this.update_layout();
744

    
745
            this.hide_nics_list();
746
            this.nics_list.hide();
747

    
748
            this.rename_view = undefined;
749
            if (!this.network.is_public()) {
750
                // allow network rename for non public networks only
751
                this.rename_view = new views.NetworkModelRenameView(this, network);
752
            }
753
            
754
            var self = this;
755
            this.network.bind('change:status', function() {
756
                self.update_layout();
757
            });
758

    
759
        },
760

    
761
        init_nics_handlers: function() {
762
            storage.nics.bind("add", _.bind(this.nic_added_handler, this, "add"));
763
            storage.nics.bind("change", _.bind(this.nic_changed_handler, this, "change"));
764
            storage.nics.bind("reset", _.bind(this.nic_changed_handler, this, "reset"));
765
            storage.nics.bind("remove", _.bind(this.nic_removed_handler, this, "remove"));
766
        },
767

    
768

    
769
        show_nics_list: function() {
770
            //if (this.nics_empty()) { return }
771
            var self = this;
772
            this.nics_list_toggler.addClass("open");
773
            this.nics_list.slideDown(function(){
774
                $(window).trigger("resize");
775
            }).closest(".network").addClass("expand");
776
            this.$(".empty-network-slot").slideDown();
777
            this.nics_visible = true;
778
        },
779

    
780
        hide_nics_list: function() {
781
            this.nics_list_toggler.removeClass("open");
782
            this.nics_list.slideUp(function(){
783
                $(window).trigger("resize");
784
            }).closest(".network").removeClass("expand");
785
            this.$(".empty-network-slot").slideUp();
786
            this.nics_visible = false;
787
        },
788
        
789
        init_toggler_handlers: function() {
790
            this.nics_list_toggler.click(_.bind(function(){
791
                if (this.nics_list.is(":visible")) {
792
                    this.hide_nics_list();
793
                } else {
794
                    this.show_nics_list();
795
                    this.fix_left_border();
796
                }
797

    
798
            }, this));
799
            $(window).bind("resize", _.bind(function() {
800
                this.fix_left_border();
801
            }, this));
802
        },
803

    
804
        init_handlers: function() {
805
            var self = this;
806

    
807

    
808
            this.$(".action-add").click(_.bind(function(e){
809
                e.preventDefault();
810
                this.network.get("actions").remove("destroy");
811
                this.show_connect_vms();
812
            }, this))
813

    
814
            this.$(".add-icon").click(_.bind(function(e){
815
                e.preventDefault();
816
                this.show_connect_vms();
817
            }, this))
818

    
819
            this.$(".net-actions .destroy a").click(_.bind(function(e){
820
                e.preventDefault();
821
                synnefo.storage.networks.each(function(n) {
822
                    n.get('actions').remove_all("disconnect");
823
                    if (!synnefo.config.network_allow_multiple_destory) {
824
                        n.get('actions').remove_all("destroy");
825
                    }
826
                });
827
                self.network.get("actions").add("destroy");
828
                self.network.get("actions").remove_all("disconnect");
829
            }, this));
830

    
831
            self.network.bind("change:actions", _.bind(function(net, action) {
832
                if (this.network.get("actions").contains("destroy")) {
833
                    this.confirm_destroy();
834
                } else {
835
                    this.cancel_destroy();
836
                }
837
            }, this));
838
            
839

    
840
            // reset pending destory action after successful removal
841
            self.network.bind("remove", _.bind(function(net){
842
                net.get("actions").remove_all("destroy");
843
            }));
844

    
845
            this.$(".net-actions button.no").click(function(e){
846
                e.preventDefault();
847
                self.network.get("actions").remove("destroy");
848
            });
849

    
850
            this.$(".net-actions button.yes").click(function(e){
851
                e.preventDefault();
852
                var el = $(this);
853
                el.closest(".confirm_single").hide();
854
                el.parent().parent().find(".selected").removeClass("selected");
855
                self.network.call('destroy', {}, function(){
856
                    el.closest(".confirm_single").removeClass("in-progress");
857
                });
858
                el.closest(".confirm_single").addClass("in-progress");
859
            });
860

    
861
            snf.ui.main.bind("view:change", _.bind(function(v) {
862
                if (v == "networks" ){ return }
863
                this.$(".confirm_single").hide();
864
                this.$("a.selected").removeClass("selected");
865
            }, this));
866
            
867
            this.$(".empty-network-slot").hide();
868
        },
869

    
870
        show_connect_vms: function() {
871
            this.$(".confirm_single").hide();
872
            this.$("a.selected").removeClass("selected");
873
            var vms = this.network.get_connectable_vms();
874
            this.parent_view.connect_machines_view.show_vms(this.network,
875
                                                            vms, [], 
876
                                                            _.bind(this.connect_vms, this));
877
        },
878

    
879
        cancel_destroy: function() {
880
            this.$(".net-actions .destroy .confirm_single").hide();
881
            this.$(".net-actions .destroy a.selected").removeClass("selected");
882
            this.$(".net-actions a").removeClass("visible");
883
        },
884

    
885
        confirm_destroy: function() {
886
            this.$(".destroy .confirm_single").show();
887
            this.$(".destroy a").addClass("selected");
888
            this.$(".net-actions a").addClass("visible");
889
        },
890

    
891
        connect_vms: function(vms) {
892
            _.each(vms, _.bind(function(vm){
893
                this.network.add_vm(vm);
894
            }, this));
895

    
896
            this.parent_view.connect_machines_view.hide();
897
        },
898

    
899
        create_el: function() {
900
            return this.$(this.tpl).clone().attr("id", this.main_view_id);
901
        },
902

    
903
        get_nic_id: function(nic) {
904
            return this.nic_id_tpl.format(nic.id);
905
        },
906

    
907
        get_nic_view: function(nic) {
908
            return $(this.get_nic_id(nic));
909
        },
910
        
911
        nic_in_network: function(nic) {
912
          return nic.get_network().id == this.network.id;
913
        },
914

    
915
        nic_added_handler: function(action, nic) {
916
            if (!this.nic_in_network(nic)) { return };
917
            this.add_or_update_nic(nic);
918
            this.update_layout();
919
            this.fix_left_border();
920
        },
921

    
922
        nic_changed_handler: function(action, nics, model, changes) {
923
            var nics = nics || [];
924

    
925
            // reset or update
926
            if (action == "reset") {
927
                nics = nics;
928
            } else {
929
                if (!_.isArray(nics)) {
930
                    nics = [nics]
931
                }
932
            }
933
            
934
            _.each(nics, _.bind(function(nic) {
935
                if (!this.nic_in_network(nic)) { return };
936
                this.add_or_update_nic(nic);
937
            }, this));
938

    
939
            this.update_layout();
940
        },
941

    
942
        nic_removed_handler: function(action, nic, model) {
943
            if (!this.nic_in_network(nic)) { return };
944
            this.fix_left_border();
945
            this.remove_nic(nic);
946
            this.update_layout();
947
        },
948

    
949
        remove_nic: function(nic) {
950
            var nic_view = this.get_nic_view(nic);
951
            if (nic_view.length) {
952
                nic_view.remove();
953
                try {
954
                    delete this.nics_views[nic.id]
955
                } catch (err) {
956
                }
957
            }
958
        },
959
        
960
        create_nic_view: function(nic) {
961
            var nic_el = $(this.nic_tpl).clone().attr({
962
                id: this.get_nic_id(nic).replace("#","")
963
            });
964
            this.nics_list.append(nic_el);
965
            this.post_nic_add(nic);
966

    
967
            if (!this.nics_views[nic.id]) {
968
                var nic_view = this.nics_views[nic.id] = new views.NetworkNICView(nic, this, this.firewall, nic_el);
969
            }
970
        },
971

    
972
        add_or_update_nic: function(nic) {
973
            if (!nic) { return };
974
                
975
            var nic_el = this.get_nic_view(nic);
976
            var nic_view = this.nics_views[nic.id];
977

    
978
            if (nic_el.length == 0) {
979
                nic_view = this.create_nic_view(nic);
980
            }
981
            
982
            if (nic_view) { nic_view.update_layout() };
983

    
984
            this.update_nic(nic);
985
            this.post_nic_update(nic);
986
        },
987

    
988
        update_nic: function(vm){},
989
        post_nic_add: function(vm){},
990
        post_nic_update: function(vm){},
991
        
992
        get_nics: function() {
993
          return this.network.get_nics();
994
        },
995

    
996
        update_nics: function(nics) {
997
            if (!nics) { nics = this.get_nics() };
998
            _.each(nics, _.bind(function(nic){
999
                this.add_or_update_nic(nic);
1000
            }, this));
1001
        },
1002

    
1003
        check_empty_nics: function() {
1004
            if (this.get_nics().length == 0) {
1005
                this.hide_nics_list();
1006
            }
1007
        },
1008

    
1009
        nics_empty: function() {
1010
            return this.get_nics().length == 0;
1011
        },
1012

    
1013
        remove: function() {
1014
            $(this.el).remove();
1015
        },
1016
        
1017
        get_name: function() {
1018
          var net_name = this.network.get('name');
1019
          if (net_name == "public") { net_name = "Internet" };
1020
          return net_name;
1021
        },
1022

    
1023
        update_layout: function() {
1024
            // has vms ???
1025
            this.check_empty_nics();
1026

    
1027
            // is expanded ???
1028
            //
1029
            // whats the network status ???
1030
            //
1031
            this.$(".machines-count").text(this.get_nics().length);
1032

    
1033
            var net_name = this.get_name();
1034
            this.$(".name-div span.name").text(net_name);
1035

    
1036
            if (this.rename_view) {
1037
                this.rename_view.update_layout();
1038
            }
1039
            
1040
            this.$(".net-status").text(this.network.state_message());
1041

    
1042
            if (this.network.in_progress())  {
1043
                this.$(".spinner").show();
1044
                this.$(".network-indicator").addClass("in-progress");
1045
            } else {
1046
                this.$(".spinner").hide();
1047
                this.$(".network-indicator").removeClass("in-progress");
1048
            }
1049
                
1050
            if (this.network.get('state') == 'PENDING') {
1051
                this.el.addClass("pending");
1052
            } else {
1053
                this.el.removeClass("pending");
1054
            }
1055

    
1056
            if (this.network.get('state') == 'ERROR') {
1057
                this.el.addClass("in-error");
1058
                this.$(".network-indicator").addClass("error-state");
1059
            } else {
1060
                this.el.removeClass("in-error");
1061
                this.$(".network-indicator").removeClass("error-state");
1062
            }
1063

    
1064
            if (synnefo.config.network_strict_destroy) {
1065
                if (this.get_nics().length == 0 && 
1066
                        !this.network.in_progress()) {
1067
                    this.el.removeClass("disable-destroy");
1068
                } else {
1069
                    this.el.addClass("disable-destroy");
1070
                }
1071
            }
1072

    
1073
            if (this.network.get("state") == "DESTROY") {
1074
                this.$(".spinner").show();
1075
                this.$(".state").addClass("destroying-state");
1076
                this.$(".actions").hide();
1077
            }
1078
        },
1079

    
1080
        // fix left border position
1081
        fix_left_border: function() {
1082
            if (!this.nics_visible) { return };
1083
            
1084
            var imgheight = 2783;
1085
            var opened_vm_height = 133 + 18;
1086
            var closed_vm_height = 61 + 20;
1087
            var additional_height = 25;
1088

    
1089
            if (!this.is_public) { 
1090
                imgheight = 2700;
1091
                additional_height = 65;
1092
            };
1093
            
1094
            var contents = this.$(".network-contents");
1095
            var last_vm = this.$(".network-machine:last .cont-toggler.open").length;
1096
            var last_vm_height = closed_vm_height;
1097
            if (last_vm > 0){
1098
                last_vm_height = opened_vm_height;
1099
            }
1100

    
1101
            var nics_opened = this.$(".network-machine .cont-toggler.open").length;
1102
            var nics_closed = this.$(".network-machine").length - nics_opened;
1103

    
1104
            var calc_height = (nics_opened * opened_vm_height) + (nics_closed * closed_vm_height) + additional_height; 
1105
            var bgpos = imgheight - calc_height + last_vm_height - 30;
1106
            this.$(".network-contents").css({'background-position':'33px ' + (-bgpos) + 'px'});
1107
        }
1108
    })
1109

    
1110
    views.PublicNetworkView = views.NetworkModelView.extend({
1111
        firewall: true,
1112
        tpl: "#public-template",
1113
        nic_tpl: "#public-nic-template",
1114
        nic_id_tpl: "#nic-{0}",
1115
        
1116
        initialize: function(network, view) {
1117
          views.PublicNetworkView.__super__.initialize.call(this, network, view);
1118
        },
1119

    
1120
        init_handlers: function(vm) {}
1121
    });
1122

    
1123
    views.GroupedPublicNetworkView = views.PublicNetworkView.extend({
1124
        main_view_id: "grouped-public",
1125

    
1126
        initialize: function(network, view) {
1127
          this.networks = {};
1128
          this.add_network(network);
1129
          views.GroupedPublicNetworkView.__super__.initialize.call(this, 
1130
                                                                   network, 
1131
                                                                   view);
1132
        },
1133
          
1134
        get_name: function() {
1135
          return synnefo.config.grouped_public_network_name || views.GroupedPublicNetworkView.__super__.get_name.call(this);
1136
        },
1137

    
1138
        nic_in_network: function(nic) {
1139
          var nic_net  = nic.get_network();
1140
          return _.filter(this.networks, function(n) { 
1141
            return nic_net.id == n.id;
1142
          }).length > 0;
1143
        },
1144

    
1145
        get_nics: function() {
1146
          var n = _.flatten(_.map(this.networks, function(n){ return n.get_nics(); }));
1147
          return n
1148
        },
1149

    
1150
        add_network: function(net) {
1151
          this.networks[net.id] = net;
1152
        },
1153

    
1154
        remove_network: function(net) {
1155
          delete this.networks[net.id];
1156
          this.update_nics();
1157
        }
1158

    
1159
    })
1160
    
1161
    views.PrivateNetworkView = views.NetworkModelView.extend({
1162
        tpl: "#private-template",
1163
        nic_tpl: "#private-nic-template",
1164
        nic_id_tpl: "#nic-{0}"
1165
    })
1166

    
1167
    views.NetworksView = views.View.extend({
1168
        
1169
        view_id: "networks",
1170
        pane: "#networks-pane",
1171
        el: "#networks-pane",
1172

    
1173
        initialize: function() {
1174
            // elements shortcuts
1175
            this.create_cont = this.$("#networks-createcontainer");
1176
            this.container = this.$("#networks-container");
1177
            this.public_list = this.$(".public-networks");
1178
            this.private_list = this.$(".private-networks");
1179
            views.NetworksView.__super__.initialize.call(this);
1180
            this.init_handlers();
1181
            this.network_views = {};
1182
            this.public_network = false;
1183
            this.update_networks(storage.networks.models);
1184
            this.create_view = new views.NetworkCreateView();
1185
            this.connect_machines_view = new views.NetworkConnectVMsOverlay();
1186
        },
1187
        
1188
        exists: function(net) {
1189
            return this.network_views[net.id];
1190
        },
1191

    
1192
        add_or_update: function(net) {
1193
            var nv = this.exists(net);
1194
            if (!nv) {
1195
                if (net.is_public()){
1196
                  if (synnefo.config.group_public_networks) {
1197
                    if (!this.public_network) {
1198
                      // grouped public not initialized
1199
                      this.public_network = this.create_network_view(net);
1200
                    } else {
1201
                      // grouped public initialized, append
1202
                      this.public_network.add_network(net);
1203
                    }
1204
                    nv = this.public_network;
1205
                  } else {
1206
                    // no grouped view asked, fallback to default create
1207
                    nv = this.create_network_view(net);
1208
                  }
1209
                } else {
1210
                  nv = this.create_network_view(net);
1211
                }
1212

    
1213
                this.network_views[net.id] = nv;
1214
                
1215
                if (net.is_public()) {
1216
                    this.public_list.append(nv.el);
1217
                    this.public_list.show();
1218
                } else {
1219
                    this.private_list.append(nv.el);
1220
                    this.private_list.show();
1221
                }
1222
            }
1223

    
1224
            // update vms
1225
            // for cases where network servers list
1226
            // get updated after vm addition and
1227
            // vm_added_handler fails to append the
1228
            // vm to the list
1229
            nv.update_nics();
1230
            nv.update_layout();
1231
        },
1232
        
1233
        create_network_view: function(net) {
1234
            if (net.is_public()) {
1235
                if (synnefo.config.group_public_networks) {
1236
                  if (self.public_network) { return self.public_network }
1237
                  return new views.GroupedPublicNetworkView(net, this);
1238
                } else {
1239
                  return new views.PublicNetworkView(net, this);
1240
                }
1241
            }
1242
            return new views.PrivateNetworkView(net, this);
1243
        },
1244
        
1245
        init_handlers: function() {
1246
            storage.networks.bind("add", _.bind(this.network_added_handler, this, "add"));
1247
            storage.networks.bind("change", _.bind(this.network_changed_handler, this, "change"));
1248
            storage.networks.bind("reset", _.bind(this.network_changed_handler, this, "reset"));
1249
            storage.networks.bind("remove", _.bind(this.network_removed_handler, this, "remove"));
1250

    
1251
            this.$("#networkscreate").click(_.bind(function(e){
1252
                e.preventDefault();
1253
                this.create_view.show();
1254
            }, this));
1255
            
1256
        },
1257

    
1258
        update_networks: function(nets) {
1259
            _.each(nets, _.bind(function(net){
1260
                if (net.get("status") == "DELETED") { return };
1261
                view = this.add_or_update(net);
1262
            }, this));
1263
        },
1264

    
1265
        show: function() {
1266
            this.container.show();
1267
            $(this.el).show();
1268
        },
1269

    
1270
        network_added_handler: function(type, net) {
1271
            this.update_networks([net]);
1272
        },
1273

    
1274
        network_changed_handler: function(type, models) {
1275
            var nets = [];
1276
            if (type == "change") {
1277
                nets = [models]
1278
            } else {
1279
                nets = models.models;
1280
            }
1281

    
1282
            this.update_networks(nets)
1283
        },
1284

    
1285
        network_removed_handler: function(type, net) {
1286
            this.remove_net(net)
1287
            if (this.private_list.find(".network").length == 0) {
1288
                this.private_list.hide();
1289
            }
1290
            
1291
        },
1292

    
1293
        network_added: function(net) {
1294
            return this.network_views[net.id];
1295
        },
1296

    
1297
        get_network_view: function(net) {
1298
            return this.network_views[net.id];
1299
        },
1300

    
1301
        remove_net: function(net) {
1302
            if (this.network_added(net)) {
1303
                var view = this.get_network_view(net);
1304
                if (view == this.public_network) {
1305
                  this.public_network.remove_network(net);
1306
                } else {
1307
                  view.remove();
1308
                }
1309
                delete this.network_views[net.id];
1310
            }
1311
        },
1312

    
1313
        __update_layout: function() {
1314
        }
1315
    });
1316

    
1317
})(this);