Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_networks_view.js @ 5b90c56d

History | View | Annotate | Download (46.6 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
        handle_vm_click: function(el) {
72
            $(el).toggleClass("selected");
73
        },
74

    
75
        init_handlers: function() {
76
            var self = this;
77
            this.list.find("li").click(function() {
78
                self.handle_vm_click($(this));
79
            });
80
            
81
            if (!this.submit_handler_set) {
82
                // avoid duplicate submits
83
                this.el.find(".create").click(_.bind(function() {
84
                    this.submit();
85
                }, this));
86
                this.submit_handler_set = true;
87
            }
88
        },
89

    
90
        reset: function() {
91
            this.list.find("li").remove();
92
        },
93

    
94
        beforeOpen: function() {
95
            this.reset();
96
            this.update_layout();
97
        },
98
        
99
        vm: function(vm) {
100
            if (vm.id) { var id = vm.id } else {var id = vm}
101
            return this.list.find(".vm-" + id);
102
        },
103

    
104
        get_selected: function() {
105
            return this.list.find(".selected").map(function() {return $(this).data('vm')})
106
        },
107

    
108
        update_layout: function() {
109
            if (this.vms.length == 0) {
110
                this.empty_message.show();
111
            } else {
112
                this.empty_message.hide();
113
            }
114

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

    
131
                vm.bind("remove", function(){ el.remove()})
132
                vm.bind("change:name", function(i,v){el.find(".title").text(v)})
133
            }, this));
134
            
135
            this.init_handlers();
136
            this.set_selected();
137
        },
138

    
139
        set_selected: function() {
140
            _.each(this.selected, _.bind(function(el){
141
                this.vm(el).addClass("selected");
142
            }, this));
143
        },
144

    
145
        show_vms: function(network, vms, selected, callback, subtitle) {
146
            this.network = network;
147
            this.reset();
148
            if (network) {
149
              this.set_subtitle(network.escape("name"));
150
            } else {
151
              this.set_subtitle(subtitle);
152
            }
153

    
154
            this.vms = vms;
155
            if (!synnefo.config.network_allow_duplicate_vm_nics && this.network) {
156
                this.vms = _.filter(this.vms, function(vm) {
157
                    return !vm.connected_to(this.network);
158
                }, this);
159
            }
160

    
161
            this.selected = selected;
162
            this.cb = callback;
163
            this.show();
164
        },
165

    
166
        submit: function() {
167
            this.cb(this.get_selected());
168
        }
169
    })
170

    
171
    views.NetworkActionsView = views.View.extend({
172
        
173
        initialize: function(view, net, el, opts) {
174
            this.parent = view
175
            this.network = net;
176
            this.el = el;
177
            
178
            this.actions = this.$(".actions");
179
            this.selected = undefined;
180

    
181
            this.destroy = this.$(".actions .destroy a");
182
            this.connect = this.$(".actions .add");
183

    
184
            this.init_handlers();
185
            this.update_layout();
186
        },
187

    
188
        init_handlers: function() {
189
            this.connect.click(_.bind(function(e){
190
                e.preventDefault();
191
            }))
192
        },
193

    
194
        update_layout: function() {
195
        }
196
    });
197

    
198
    views.NetworkCreateView = views.Overlay.extend({
199
        view_id: "network_create_view",
200
        content_selector: "#networks-create-content",
201
        css_class: 'overlay-networks-create overlay-info',
202
        overlay_id: "network-create-overlay",
203

    
204
        title: "Create new private network",
205
        subtitle: "Networks",
206

    
207
        initialize: function(options) {
208
            views.NetworkCreateView.__super__.initialize.apply(this);
209

    
210
            this.create_button = this.$("form .form-action.create");
211
            this.text = this.$(".network-create-name");
212
            this.form = this.$("form");
213

    
214
            this.dhcp_select = this.$("#network-create-dhcp");
215
            this.type_select = this.$("#network-create-type");
216
            this.subnet_select = this.$("#network-create-subnet");
217
            this.subnet_custom = this.$("#network-create-subnet-custom");
218
                
219
            this.dhcp_form = this.$("#network-create-dhcp-fields");
220
            
221
            this.subnet_select.find(".subnet").remove();
222
            _.each(synnefo.config.network_suggested_subnets, function(subnet){
223
                this.subnet_select.append($('<option value='+subnet+' class="subnet">'+subnet+'</option>'));
224
            }, this);
225

    
226
            this.type_select.find(".subnet").remove();
227
            _.each(synnefo.config.network_available_types, function(name, value){
228
                this.type_select.append($('<option value='+value+' class="subnet">'+name+'</option>'));
229
            }, this);
230
            
231
            if (_.keys(synnefo.config.network_available_types).length <= 1) {
232
                this.type_select.closest(".form-field").hide();
233
            }
234

    
235
            this.check_dhcp_form();
236
            this.init_handlers();
237
        },
238

    
239
        reset_dhcp_form: function() {
240
          this.subnet_select.find("option")[0].selected = 1;
241
          this.subnet_custom.val("");
242
        },
243

    
244
        check_dhcp_form: function() {
245
            if (this.dhcp_select.is(":checked")) {
246
                this.dhcp_form.show();
247
            } else {
248
                this.dhcp_form.hide();
249
            }
250
            
251
            if (this.subnet_select.val() == "custom") {
252
                this.subnet_custom.show();
253
            } else {
254
                this.subnet_custom.hide();
255
            }
256
        },
257

    
258
        init_handlers: function() {
259

    
260
            this.dhcp_select.click(_.bind(function(e){
261
                this.check_dhcp_form();
262
                this.reset_dhcp_form();
263
            }, this));
264

    
265
            this.subnet_select.change(_.bind(function(e){
266
                this.check_dhcp_form();
267
                if (this.subnet_custom.is(":visible")) {
268
                    this.subnet_custom.focus();
269
                }
270
            }, this));
271

    
272
            this.create_button.click(_.bind(function(e){
273
                this.submit();
274
            }, this));
275

    
276
            this.form.submit(_.bind(function(e){
277
                e.preventDefault();
278
                this.submit;
279
                return false;
280
            }, this))
281

    
282
            this.text.keypress(_.bind(function(e){
283
                if (e.which == 13) {this.submit()};
284
            },this))
285
        },
286

    
287
        submit: function() {
288
            if (this.validate()) {
289
                this.create();
290
            };
291
        },
292
        
293
        validate: function() {
294
            // sanitazie
295
            var t = this.text.val();
296
            t = t.replace(/^\s+|\s+$/g,"");
297
            this.text.val(t);
298

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

    
322
            return true;
323
        },
324
        
325
        get_next_available_subnet: function() {
326
            var auto_tpl = synnefo.config.automatic_network_range_format;
327
            if (!auto_tpl) {
328
                return null
329
            }
330
            var index = 0;
331
            var subnet = auto_tpl.format(index);
332
            var networks = synnefo.storage.networks;
333
            var check_existing = function(n) { return n.get('cidr') == subnet }
334
            while (networks.filter(check_existing).length > 0 && index <= 255) {
335
                index++;
336
                subnet = auto_tpl.format(index); 
337
            }
338
            return subnet;
339
        },
340

    
341
        create: function() {
342
            this.create_button.addClass("in-progress");
343

    
344
            var name = this.text.val();
345
            var dhcp = this.dhcp_select.is(":checked");
346
            var subnet = null;
347
            var type = this.type_select.val();
348

    
349
            if (dhcp) {
350
                if (this.subnet_select.val() == "custom") {
351
                    subnet = this.subnet_custom.val();
352
                } else if (this.subnet_select.val() == "auto") {
353
                    subnet = this.get_next_available_subnet()
354
                } else {
355
                    subnet = this.subnet_select.val();
356
                }
357
                
358
            }
359

    
360
            snf.storage.networks.create(name, type, subnet, dhcp, _.bind(function(){
361
                this.hide();
362
            }, this));
363
        },
364

    
365
        beforeOpen: function() {
366
            this.create_button.removeClass("in-progress")
367
            this.text.closest(".form-field").removeClass("error");
368
            this.text.val("");
369
            this.text.show();
370
            this.text.focus();
371
            this.subnet_custom.val("");
372
            this.subnet_select.val("auto");
373
            this.dhcp_select.attr("checked", true);
374
            this.type_select.val(_.keys(synnefo.config.network_available_types)[0]);
375
            this.check_dhcp_form();
376
        },
377

    
378
        onOpen: function() {
379
            this.text.focus();
380
        }
381
    });
382

    
383
    views.NetworkNICView = views.View.extend({
384

    
385
        initialize: function(nic, parent, firewall_controls, el) {
386
            this.firewall_controls = firewall_controls || false;
387
            this.nic = nic;
388
            this.vm = nic.get_vm();
389
            // parent view di
390
            this.parent = parent;
391
            // TODO make it better
392
            this.el = el || this.parent.get_nic_view(nic);
393

    
394
            this.init_layout();
395
            this.update_layout();
396

    
397
            this.disconnect = this.$(".action-disconnect");
398
            this.confirm_el = this.$(".confirm_single");
399
            this.cancel = this.$("button.no");
400
            this.confirm = this.$("button.yes");
401
            this.details = this.$(".action-details");
402
            this.vm_connect = this.$(".machine-connect");
403
            this.actions = this.$(".net-vm-actions");
404

    
405
            this.init_handlers();
406
            this.connect_overlay = new views.VMConnectView();
407
            
408
            this.firewall_view = undefined;
409
            if (this.firewall_controls) {
410
                this.firewall_view = new views.FirewallEditView(this.nic, this.parent.network, this);
411
            }
412

    
413
        },
414
        
415
        reset_all_net_actions: function(act_types) {
416
            synnefo.storage.networks.each(function(n){
417
                var actions = n.get('actions');
418
                _.each(act_types, function(type){
419
                    actions.remove_all(type);
420
                })
421
            })
422
        },
423

    
424
        init_handlers: function() {
425
            if (!this.parent.network.is_public()) {
426
                this.disconnect.click(_.bind(function(e){
427
                    e.preventDefault();
428
                    this.reset_all_net_actions(['destroy','disconnect']);
429
                    this.parent.network.get("actions").remove_all("disconnect");
430
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
431
                    this.parent.network.get("actions").remove("destroy");
432
                }, this));
433
                this.cancel.click(_.bind(function(e){
434
                    this.parent.network.get("actions").remove("disconnect", this.nic.id);
435
                    e.preventDefault()
436
                }, this));
437

    
438
                this.confirm.click(_.bind(function(e){
439
                    e.preventDefault()
440
                    this.disconnect_nic();
441
                    this.confirm_el.hide();
442
                    this.disconnect.removeClass("selected");
443
                    this.actions.find("a").removeClass("visible");
444
                }, this));
445

    
446
                snf.ui.main.bind("view:change", _.bind(function(v) {
447
                    if (v == "networks" ){ return }
448
                    this.confirm_el.hide();
449
                    this.disconnect.removeClass("selected");
450
                }, this));
451

    
452
                this.$(".remove-icon").click(_.bind(function(){
453
                    this.reset_all_net_actions(['destroy','disconnect']);
454
                    this.parent.network.get("actions").remove_all("disconnect");
455
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
456
                    this.parent.network.get("actions").remove("destroy");
457
                }, this));
458

    
459
                this.vm_connect.click(_.bind(function() {
460
                    this.connect_overlay.show(this.vm);
461
                }, this));
462
                
463
                this.parent.network.bind("change:actions", _.bind(function(model, action){
464
                    if (this.parent.network.get("actions").contains("disconnect", this.nic.id)) {
465
                        this.confirm_disconnect();
466
                    } else {
467
                        this.cancel_disconnect();
468
                    }
469
                }, this));
470
            }
471
            
472
            var vm = this.vm;
473
            this.details.click(function(e){
474
                e.preventDefault();
475
                snf.ui.main.show_vm_details(vm);
476
            });
477

    
478
        },
479

    
480
        cancel_disconnect: function() {
481
            this.confirm_el.hide();
482
            this.disconnect.removeClass("selected");
483
            this.$(".net-vm-actions a").removeClass("visible");
484
        },
485

    
486
        confirm_disconnect: function() {
487
            this.confirm_el.show();
488
            this.disconnect.addClass("selected");
489
            this.$(".net-vm-actions a").addClass("visible");
490
        },
491

    
492
        init_layout: function() {
493
            if (!this.firewall_controls) { return };
494
        },
495

    
496
        update_layout: function() {
497
            this.$(".vm-name").text(snf.util.truncate(this.vm.get("name"), 40));
498
            this.$("img.logo").attr("src", ui.helpers.vm_icon_path(this.vm, "medium"));
499

    
500
            if (this.firewall_view) {
501
                this.$(".ipv4-text").text(this.nic.get_v4_address());
502
                this.$(".ipv6-text").text(this.nic.get_v6_address());
503
            }
504

    
505
            if (this.firewall_view) {
506
                this.firewall_view.update_layout();
507
            }
508

    
509
            if (!this.firewall_view) {
510
                this.$(".ip4-container").hide();
511
                this.$(".ip6-container").hide();
512
                
513
                if (this.nic.get("ipv4")) {
514
                    this.$(".ipv4-text").text(this.nic.get_v4_address());
515
                    this.$(".ip4-container").show();
516
                    this.$(".machine-connect .content").hide();
517
                } else if (this.nic.get("ipv6")) {
518
                    this.$(".ipv6-text").text(this.nic.get_v6_address());
519
                    this.$(".ip6-container").show();
520
                    this.$(".machine-connect .content").hide();
521
                } else {
522
                    this.$(".machine-connect .content").show();
523
                }
524
            } else {
525
            }
526
        },
527

    
528
        disconnect_nic: function() {
529
            this.$("a.selected").removeClass("selected");
530
            this.nic.get_network().remove_nic(this.nic);
531
        }
532
    })
533

    
534
    views.NetworkModelRenameView = views.View.extend({
535
        initialize: function(parent, network) {
536
            this.parent = parent;
537
            this.network = network;
538
            this.el = this.parent.el.find(".name-div");
539

    
540
            this.icon = this.$(".rename-network");
541
            this.save = this.$("span.save");
542
            this.cancel = this.$("span.cancel");
543
            this.buttons = this.$(".editbuttons");
544
            this.name = this.$("span.name");
545
            this.editing = false;
546
            this.init_handlers();
547
            this.update_layout();
548
        },
549

    
550
        init_handlers: function() {
551
            this.icon.click(_.bind(function(){
552
                this.editing = true;
553
                this.update_layout();
554
            }, this));
555
            this.cancel.click(_.bind(function(){
556
                this.editing = false;
557
                this.update_layout();
558
            }, this));
559
            this.save.click(_.bind(function(){
560
                this.submit();
561
            }, this))
562
        },
563
        
564
        submit: function() {
565
            var value = _(this.input.val()).trim();
566
            if (value == "") { return }
567

    
568
            this.network.rename(value, _.bind(function(){
569
                this.editing = false;
570
                this.update_layout();
571
            }, this));
572
        },
573

    
574
        create_input: function() {
575
            this.input = $('<input type="text" class="network-rename-input" />');
576
            this.input.val(this.network.get("name"));
577
            this.el.append(this.input);
578
            this.input.focus();
579
            this.input.bind("keydown", _.bind(function(ev){
580
                ev.keyCode = ev.keyCode || ev.which;
581
                if (ev.keyCode == 13) { this.submit(); };
582
                if (ev.keyCode == 27) {this.editing = false; this.update_layout()};
583
            }, this));
584
        },
585

    
586
        remove_input: function() {
587
            if (!this.input) { return }
588
            this.input.remove();
589
        },
590

    
591
        update_layout: function() {
592
            if (this.editing) {
593
                if (this.buttons.is(":visible")) { return }
594
                this.icon.hide();
595
                this.buttons.show();
596
                this.create_input();
597
                this.name.hide();
598
            } else {
599
                this.buttons.hide();
600
                this.remove_input();
601
                this.name.show();
602
                this.icon.show();
603
            }
604
        }
605
    })
606

    
607
    views.FirewallEditView = views.View.extend({
608

    
609
        initialize: function(nic, network, parent) {
610
            this.parent = parent;
611
            this.vm = nic.get_vm();
612
            this.nic = nic;
613
            this.network = network;
614
            this.el = this.parent.el;
615

    
616
            views.FirewallEditView.__super__.initialize.apply(this);
617

    
618
            // elements
619
            this.toggler = this.$(".firewall-toggle");
620
            this.indicator = this.$(".machines-label span");
621
            this.progress = this.$(".network-progress-indicator");
622
            this.content = this.$(".firewall-content");
623
            this.inputs = this.$("input[type=radio]");
624
            this.labels = this.$("span.checkbox-legends, label.checkbox-legends");
625
            this.apply = this.$(".firewall-apply");
626

    
627
            this.$(".firewall-content").hide();
628
            this.$(".firewall-content input[type=radio]").attr("name", "firewall-opt-for-{0}".format(this.vm.id))
629
            var mode = this.vm.get_firewall_profile();
630
            this.$(".firewall-content input[value={0}]".format(mode)).attr("checked", true);
631

    
632
            this.init_handlers();
633
            this.update_layout();
634

    
635
            var self = this;
636
            this.nic.bind("change:pending_firewall_sending", function(nic, value) {
637
                if (value) {
638
                    self.apply.addClass("in-progress");       
639
                    self.progress.show();
640
                } else {
641
                    self.apply.removeClass("in-progress");       
642
                    self.progress.hide();
643
                    self.toggler.click();
644
                }
645
            });
646

    
647
            this.nic.bind("change:firewallProfile", function(nic){
648
                self.update_layout();
649
                self.reset_value();
650
            })
651

    
652
        },
653
        
654
        _get_selected: function() {
655
            return this.inputs.filter(":checked");
656
        },
657

    
658
        reset_selected: function() {
659
        },
660

    
661
        submit: function() {
662
        },
663

    
664
        reset_value: function() {
665
            this.inputs.filter("[value={0}]".format(
666
              this.nic.get('firewallProfile'))).attr("checked", true);
667
        },
668

    
669
        init_handlers: function() {
670
            this.toggler.click(_.bind(function(){
671
                cont = this.content;
672
                if (cont.is(":visible")) {
673
                    this.hide_firewall();
674
                    this.reset_value();
675
                } else {
676
                    this.show_firewall();
677
                }
678

    
679
                $(window).trigger("resize");
680
            }, this))
681
            
682
            this.apply.click(_.bind(function(){
683
                this.nic.set_firewall(this.value());
684
            }, this))
685

    
686
            this.inputs.change(_.bind(function(){
687
                this.update_selected();
688
            }, this))
689
            
690
            var self = this;
691
            this.$(".checkbox-legends").click(function(el) {
692
                var el = $(this);
693
                el.prev().click();
694
                self.update_selected();
695
            })
696
        },
697

    
698
        update_selected: function() {
699
            this.update_layout();
700
        },
701

    
702
        show_firewall: function() {
703
            this.content.slideDown(100, function(){$(window).trigger("resize")});
704
            this.toggler.addClass("open");
705
        },
706

    
707
        hide_firewall: function() {
708
            this.content.slideUp(100, function(){$(window).trigger("resize")});
709
            this.toggler.removeClass("open");
710
        },
711

    
712
        value: function() {
713
            return this._get_selected().val();
714
        },
715

    
716
        update_layout: function() {
717
            if (this.value() == this.vm.get_firewall_profile()) {
718
                this.apply.hide();
719
            } else {
720
                this.apply.show();
721
            }
722

    
723
            var profile = this.vm.get_firewall_profile();
724
            if (this.vm.has_firewall(this.network.id)) {
725
                this.$(".firewall-toggle .label span").text("On");
726
                this.$(".firewall-toggle .label span").removeClass("firewall-off");
727
                this.$(".firewall-toggle .label span").addClass("firewall-on");
728
            } else {
729
                this.$(".firewall-toggle .label span").text("Off");
730
                this.$(".firewall-toggle .label span").removeClass("firewall-on");
731
                this.$(".firewall-toggle .label span").addClass("firewall-off");
732
            }
733
            
734
            this.$("span.checkbox-legends").removeClass("current");
735
            this.inputs.filter("[value={0}]".format(profile)).next().addClass("current");
736
            
737
        }
738
    })
739

    
740
    views.NetworkModelView = views.View.extend({
741
        
742
        firewall: false,
743

    
744
        initialize: function(network, view) {
745
            this.parent_view = view;
746
            this.network = network;
747
            this.main_view_id = this.main_view_id ? this.main_view_id : "networks_view_" + network.id;
748
            this.is_public = network.is_public();
749

    
750
            this.init_nics_handlers();
751
            
752
            this.view_id = "networks_view_" + network.id;
753
            views.NetworkModelView.__super__.initialize.call(this);
754

    
755
            this.nics_views = {};
756

    
757
            this.el = this.create_el();
758

    
759
            // element helpers
760
            this.nics_list = this.$(".machines-list");
761
            this.nics_list_toggler = this.$(".list-toggle");
762
            
763
            this.init_handlers();
764
            this.init_toggler_handlers();
765
            this.update_nics();
766
            this.update_layout();
767

    
768
            this.hide_nics_list();
769
            this.nics_list.hide();
770

    
771
            this.rename_view = undefined;
772
            if (!this.network.is_public()) {
773
                // allow network rename for non public networks only
774
                this.rename_view = new views.NetworkModelRenameView(this, network);
775
            }
776
            
777
            var self = this;
778
            this.network.bind('change:status', function() {
779
                self.update_layout();
780
            });
781

    
782
        },
783

    
784
        init_nics_handlers: function() {
785
            storage.nics.bind("add", _.bind(this.nic_added_handler, this, "add"));
786
            storage.nics.bind("change", _.bind(this.nic_changed_handler, this, "change"));
787
            storage.nics.bind("reset", _.bind(this.nic_changed_handler, this, "reset"));
788
            storage.nics.bind("remove", _.bind(this.nic_removed_handler, this, "remove"));
789
        },
790

    
791

    
792
        show_nics_list: function() {
793
            //if (this.nics_empty()) { return }
794
            var self = this;
795
            this.nics_list_toggler.addClass("open");
796
            this.nics_list.slideDown(function(){
797
                $(window).trigger("resize");
798
            }).closest(".network").addClass("expand");
799
            this.$(".empty-network-slot").slideDown();
800
            this.nics_visible = true;
801
        },
802

    
803
        hide_nics_list: function() {
804
            this.nics_list_toggler.removeClass("open");
805
            this.nics_list.slideUp(function(){
806
                $(window).trigger("resize");
807
            }).closest(".network").removeClass("expand");
808
            this.$(".empty-network-slot").slideUp();
809
            this.nics_visible = false;
810
        },
811
        
812
        init_toggler_handlers: function() {
813
            this.nics_list_toggler.click(_.bind(function(){
814
                if (this.nics_list.is(":visible")) {
815
                    this.hide_nics_list();
816
                } else {
817
                    this.show_nics_list();
818
                    this.fix_left_border();
819
                }
820

    
821
            }, this));
822
            $(window).bind("resize", _.bind(function() {
823
                this.fix_left_border();
824
            }, this));
825
        },
826

    
827
        init_handlers: function() {
828
            var self = this;
829

    
830

    
831
            this.$(".action-add").click(_.bind(function(e){
832
                e.preventDefault();
833
                this.network.get("actions").remove("destroy");
834
                this.show_connect_vms();
835
            }, this))
836

    
837
            this.$(".add-icon").click(_.bind(function(e){
838
                e.preventDefault();
839
                this.show_connect_vms();
840
            }, this))
841

    
842
            this.$(".net-actions .destroy a").click(_.bind(function(e){
843
                e.preventDefault();
844
                synnefo.storage.networks.each(function(n) {
845
                    n.get('actions').remove_all("disconnect");
846
                    if (!synnefo.config.network_allow_multiple_destory) {
847
                        n.get('actions').remove_all("destroy");
848
                    }
849
                });
850
                self.network.get("actions").add("destroy");
851
                self.network.get("actions").remove_all("disconnect");
852
            }, this));
853

    
854
            self.network.bind("change:actions", _.bind(function(net, action) {
855
                if (this.network.get("actions").contains("destroy")) {
856
                    this.confirm_destroy();
857
                } else {
858
                    this.cancel_destroy();
859
                }
860
            }, this));
861
            
862

    
863
            // reset pending destory action after successful removal
864
            self.network.bind("remove", _.bind(function(net){
865
                net.get("actions").remove_all("destroy");
866
            }));
867

    
868
            this.$(".net-actions button.no").click(function(e){
869
                e.preventDefault();
870
                self.network.get("actions").remove("destroy");
871
            });
872

    
873
            this.$(".net-actions button.yes").click(function(e){
874
                e.preventDefault();
875
                var el = $(this);
876
                el.closest(".confirm_single").hide();
877
                el.parent().parent().find(".selected").removeClass("selected");
878
                self.network.call('destroy', {}, function(){
879
                    el.closest(".confirm_single").removeClass("in-progress");
880
                });
881
                el.closest(".confirm_single").addClass("in-progress");
882
            });
883

    
884
            snf.ui.main.bind("view:change", _.bind(function(v) {
885
                if (v == "networks" ){ return }
886
                this.$(".confirm_single").hide();
887
                this.$("a.selected").removeClass("selected");
888
            }, this));
889
            
890
            this.$(".empty-network-slot").hide();
891
        },
892

    
893
        show_connect_vms: function() {
894
            this.$(".confirm_single").hide();
895
            this.$("a.selected").removeClass("selected");
896
            var vms = this.network.get_connectable_vms();
897
            this.parent_view.connect_machines_view.show_vms(this.network,
898
                                                            vms, [], 
899
                                                            _.bind(this.connect_vms, this));
900
        },
901

    
902
        cancel_destroy: function() {
903
            this.$(".net-actions .destroy .confirm_single").hide();
904
            this.$(".net-actions .destroy a.selected").removeClass("selected");
905
            this.$(".net-actions a").removeClass("visible");
906
        },
907

    
908
        confirm_destroy: function() {
909
            this.$(".destroy .confirm_single").show();
910
            this.$(".destroy a").addClass("selected");
911
            this.$(".net-actions a").addClass("visible");
912
        },
913

    
914
        connect_vms: function(vms) {
915
            _.each(vms, _.bind(function(vm){
916
                this.network.add_vm(vm, function() {
917
                  if (!synnefo.config.private_networks_nic_hotplug) {
918
                    vm.require_reboot();
919
                  }
920
                });
921
            }, this));
922

    
923
            this.parent_view.connect_machines_view.hide();
924
        },
925

    
926
        create_el: function() {
927
            return this.$(this.tpl).clone().attr("id", this.main_view_id);
928
        },
929

    
930
        get_nic_id: function(nic) {
931
            return this.nic_id_tpl.format(nic.id);
932
        },
933

    
934
        get_nic_view: function(nic) {
935
            return $(this.get_nic_id(nic));
936
        },
937
        
938
        nic_in_network: function(nic) {
939
          return nic.get_network().id == this.network.id;
940
        },
941

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

    
949
        nic_changed_handler: function(action, nics, model, changes) {
950
            var nics = nics || [];
951

    
952
            // reset or update
953
            if (action == "reset") {
954
                nics = nics;
955
            } else {
956
                if (!_.isArray(nics)) {
957
                    nics = [nics]
958
                }
959
            }
960
            
961
            _.each(nics, _.bind(function(nic) {
962
                if (!this.nic_in_network(nic)) { return };
963
                this.add_or_update_nic(nic);
964
            }, this));
965

    
966
            this.update_layout();
967
        },
968

    
969
        nic_removed_handler: function(action, nic, model) {
970
            if (!this.nic_in_network(nic)) { return };
971
            this.fix_left_border();
972
            this.remove_nic(nic);
973
            this.update_layout();
974
        },
975

    
976
        remove_nic: function(nic) {
977
            var nic_view = this.get_nic_view(nic);
978
            if (nic_view.length) {
979
                nic_view.remove();
980
                try {
981
                    delete this.nics_views[nic.id]
982
                } catch (err) {
983
                }
984
            }
985
        },
986
        
987
        create_nic_view: function(nic) {
988
            var nic_el = $(this.nic_tpl).clone().attr({
989
                id: this.get_nic_id(nic).replace("#","")
990
            });
991
            this.nics_list.append(nic_el);
992
            this.post_nic_add(nic);
993

    
994
            if (!this.nics_views[nic.id]) {
995
                var nic_view = this.nics_views[nic.id] = new views.NetworkNICView(nic, this, this.firewall, nic_el);
996
            }
997
        },
998

    
999
        add_or_update_nic: function(nic) {
1000
            if (!nic) { return };
1001
                
1002
            var nic_el = this.get_nic_view(nic);
1003
            var nic_view = this.nics_views[nic.id];
1004

    
1005
            if (nic_el.length == 0) {
1006
                nic_view = this.create_nic_view(nic);
1007
            }
1008
            
1009
            if (nic_view) { nic_view.update_layout() };
1010

    
1011
            this.update_nic(nic);
1012
            this.post_nic_update(nic);
1013
        },
1014

    
1015
        update_nic: function(vm){},
1016
        post_nic_add: function(vm){},
1017
        post_nic_update: function(vm){},
1018
        
1019
        get_nics: function() {
1020
          return this.network.get_nics();
1021
        },
1022

    
1023
        update_nics: function(nics) {
1024
            if (!nics) { nics = this.get_nics() };
1025
            _.each(nics, _.bind(function(nic){
1026
                this.add_or_update_nic(nic);
1027
            }, this));
1028
        },
1029

    
1030
        check_empty_nics: function() {
1031
            if (this.get_nics().length == 0) {
1032
                this.hide_nics_list();
1033
            }
1034
        },
1035

    
1036
        nics_empty: function() {
1037
            return this.get_nics().length == 0;
1038
        },
1039

    
1040
        remove: function() {
1041
            $(this.el).remove();
1042
        },
1043
        
1044
        get_name: function() {
1045
          var net_name = this.network.get('name');
1046
          if (net_name == "public") { net_name = "Internet" };
1047
          return net_name;
1048
        },
1049

    
1050
        update_layout: function() {
1051
            // has vms ???
1052
            this.check_empty_nics();
1053

    
1054
            // is expanded ???
1055
            //
1056
            // whats the network status ???
1057
            //
1058
            this.$(".machines-count").text(this.get_nics().length);
1059

    
1060
            var net_name = this.get_name();
1061
            this.$(".name-div span.name").text(net_name);
1062

    
1063
            if (this.rename_view) {
1064
                this.rename_view.update_layout();
1065
            }
1066
            
1067
            this.$(".net-status").text(this.network.state_message());
1068

    
1069
            if (this.network.in_progress())  {
1070
                this.$(".spinner").show();
1071
                this.$(".network-indicator").addClass("in-progress");
1072
            } else {
1073
                this.$(".spinner").hide();
1074
                this.$(".network-indicator").removeClass("in-progress");
1075
            }
1076
                
1077
            if (this.network.get('state') == 'PENDING') {
1078
                this.el.addClass("pending");
1079
            } else {
1080
                this.el.removeClass("pending");
1081
            }
1082

    
1083
            if (this.network.get('state') == 'ERROR') {
1084
                this.el.addClass("in-error");
1085
                this.$(".network-indicator").addClass("error-state");
1086
            } else {
1087
                this.el.removeClass("in-error");
1088
                this.$(".network-indicator").removeClass("error-state");
1089
            }
1090

    
1091
            if (synnefo.config.network_strict_destroy) {
1092
                if (this.get_nics().length == 0 && 
1093
                        !this.network.in_progress()) {
1094
                    this.el.removeClass("disable-destroy");
1095
                } else {
1096
                    this.el.addClass("disable-destroy");
1097
                }
1098
            }
1099

    
1100
            if (this.network.get("state") == "DESTROY") {
1101
                this.$(".spinner").show();
1102
                this.$(".state").addClass("destroying-state");
1103
                this.$(".actions").hide();
1104
            } else {
1105
                this.$(".state").removeClass("destroying-state");
1106
                this.$(".actions").show();
1107
                this.$(".actions a").removeClass("visible");
1108
            }
1109
        },
1110

    
1111
        // fix left border position
1112
        fix_left_border: function(force) {
1113
            if (!this.nics_visible && !force) { return };
1114
            
1115
            var imgheight = 2783;
1116
            var opened_vm_height = 133 + 18;
1117
            var closed_vm_height = 61 + 20;
1118
            var additional_height = 25;
1119

    
1120
            if (!this.is_public) { 
1121
                imgheight = 2700;
1122
                additional_height = 65;
1123
            };
1124
            
1125
            var contents = this.$(".network-contents");
1126
            var last_vm = this.$(".network-machine:last .cont-toggler.open").length;
1127
            var last_vm_height = closed_vm_height;
1128
            if (last_vm > 0){
1129
                last_vm_height = opened_vm_height;
1130
            }
1131

    
1132
            var nics_opened = this.$(".network-machine .cont-toggler.open").length;
1133
            var nics_closed = this.$(".network-machine").length - nics_opened;
1134

    
1135
            var calc_height = (nics_opened * opened_vm_height) + (nics_closed * closed_vm_height) + additional_height; 
1136
            var bgpos = imgheight - calc_height + last_vm_height - 30;
1137
            this.$(".network-contents").css({'background-position':'33px ' + (-bgpos) + 'px'});
1138
        }
1139
    })
1140

    
1141
    views.PublicNetworkView = views.NetworkModelView.extend({
1142
        firewall: true,
1143
        tpl: "#public-template",
1144
        nic_tpl: "#public-nic-template",
1145
        nic_id_tpl: "#nic-{0}",
1146
        
1147
        initialize: function(network, view) {
1148
          views.PublicNetworkView.__super__.initialize.call(this, network, view);
1149
          this.fix_left_border(1);
1150
        },
1151

    
1152
        init_handlers: function(vm) {
1153
          $(window).bind("resize", _.bind(function() {
1154
              this.fix_left_border();
1155
          }, this));
1156
        }
1157
    });
1158

    
1159
    views.GroupedPublicNetworkView = views.PublicNetworkView.extend({
1160
        main_view_id: "grouped-public",
1161

    
1162
        initialize: function(network, view) {
1163
          this.networks = {};
1164
          this.add_network(network);
1165
          views.GroupedPublicNetworkView.__super__.initialize.call(this, 
1166
                                                                   network, 
1167
                                                                   view);
1168
        },
1169
          
1170
        get_name: function() {
1171
          return synnefo.config.grouped_public_network_name || views.GroupedPublicNetworkView.__super__.get_name.call(this);
1172
        },
1173

    
1174
        nic_in_network: function(nic) {
1175
          var nic_net  = nic.get_network();
1176
          return _.filter(this.networks, function(n) { 
1177
            return nic_net.id == n.id;
1178
          }).length > 0;
1179
        },
1180

    
1181
        get_nics: function() {
1182
          var n = _.flatten(_.map(this.networks, function(n){ return n.get_nics(); }));
1183
          return n
1184
        },
1185

    
1186
        add_network: function(net) {
1187
          this.networks[net.id] = net;
1188
        },
1189

    
1190
        remove_network: function(net) {
1191
          delete this.networks[net.id];
1192
          this.update_nics();
1193
        }
1194

    
1195
    })
1196
    
1197
    views.PrivateNetworkView = views.NetworkModelView.extend({
1198
        tpl: "#private-template",
1199
        nic_tpl: "#private-nic-template",
1200
        nic_id_tpl: "#nic-{0}"
1201
    })
1202

    
1203
    views.NetworksView = views.View.extend({
1204
        
1205
        view_id: "networks",
1206
        pane: "#networks-pane",
1207
        el: "#networks-pane",
1208

    
1209
        initialize: function() {
1210
            // elements shortcuts
1211
            this.create_cont = this.$("#networks-createcontainer");
1212
            this.container = this.$("#networks-container");
1213
            this.public_list = this.$(".public-networks");
1214
            this.private_list = this.$(".private-networks");
1215
            views.NetworksView.__super__.initialize.call(this);
1216
            this.init_handlers();
1217
            this.network_views = {};
1218
            this.public_network = false;
1219
            this.update_networks(storage.networks.models);
1220
            this.create_view = new views.NetworkCreateView();
1221
            this.connect_machines_view = new views.NetworkConnectVMsOverlay();
1222
        },
1223
        
1224
        exists: function(net) {
1225
            return this.network_views[net.id];
1226
        },
1227

    
1228
        add_or_update: function(net) {
1229
            var nv = this.exists(net);
1230
            if (!nv) {
1231
                if (net.is_public()){
1232
                  if (synnefo.config.group_public_networks) {
1233
                    if (!this.public_network) {
1234
                      // grouped public not initialized
1235
                      this.public_network = this.create_network_view(net);
1236
                    } else {
1237
                      // grouped public initialized, append
1238
                      this.public_network.add_network(net);
1239
                    }
1240
                    nv = this.public_network;
1241
                  } else {
1242
                    // no grouped view asked, fallback to default create
1243
                    nv = this.create_network_view(net);
1244
                  }
1245
                } else {
1246
                  nv = this.create_network_view(net);
1247
                }
1248

    
1249
                this.network_views[net.id] = nv;
1250
                
1251
                if (net.is_public()) {
1252
                    this.public_list.append(nv.el);
1253
                    this.public_list.show();
1254
                } else {
1255
                    this.private_list.append(nv.el);
1256
                    this.private_list.show();
1257
                }
1258
            }
1259

    
1260
            // update vms
1261
            // for cases where network servers list
1262
            // get updated after vm addition and
1263
            // vm_added_handler fails to append the
1264
            // vm to the list
1265
            nv.update_nics();
1266
            nv.update_layout();
1267
        },
1268
        
1269
        create_network_view: function(net) {
1270
            if (net.is_public()) {
1271
                if (synnefo.config.group_public_networks) {
1272
                  if (self.public_network) { return self.public_network }
1273
                  return new views.GroupedPublicNetworkView(net, this);
1274
                } else {
1275
                  return new views.PublicNetworkView(net, this);
1276
                }
1277
            }
1278
            return new views.PrivateNetworkView(net, this);
1279
        },
1280
        
1281
        init_handlers: function() {
1282
            storage.networks.bind("add", _.bind(this.network_added_handler, this, "add"));
1283
            storage.networks.bind("change", _.bind(this.network_changed_handler, this, "change"));
1284
            storage.networks.bind("reset", _.bind(this.network_changed_handler, this, "reset"));
1285
            storage.networks.bind("remove", _.bind(this.network_removed_handler, this, "remove"));
1286

    
1287
            this.$("#networkscreate").click(_.bind(function(e){
1288
              e.preventDefault();
1289
              if ($(this.$("#networkscreate")).hasClass("disabled")) { return }
1290
              this.create_view.show();
1291
            }, this));
1292
            
1293
            var self = this;
1294
            storage.networks.bind("quota_reached", function(){
1295
              self.$("#networkscreate").addClass("disabled").attr("title", 
1296
                                                            "Networks limit reached");
1297
            });
1298
            storage.networks.bind("quota_free", function(){
1299
              self.$("#networkscreate").removeClass("disabled").attr("title", 
1300
                                                            "");
1301
            });
1302
        },
1303

    
1304
        update_networks: function(nets) {
1305
            _.each(nets, _.bind(function(net){
1306
                if (net.get("status") == "DELETED") { return };
1307
                view = this.add_or_update(net);
1308
            }, this));
1309
        },
1310

    
1311
        show: function() {
1312
            this.container.show();
1313
            $(this.el).show();
1314
        },
1315

    
1316
        network_added_handler: function(type, net) {
1317
            this.update_networks([net]);
1318
        },
1319

    
1320
        network_changed_handler: function(type, models) {
1321
            var nets = [];
1322
            if (type == "change") {
1323
                nets = [models]
1324
            } else {
1325
                nets = models.models;
1326
            }
1327

    
1328
            this.update_networks(nets)
1329
        },
1330

    
1331
        network_removed_handler: function(type, net) {
1332
            this.remove_net(net)
1333
            if (this.private_list.find(".network").length == 0) {
1334
                this.private_list.hide();
1335
            }
1336
            
1337
        },
1338

    
1339
        network_added: function(net) {
1340
            return this.network_views[net.id];
1341
        },
1342

    
1343
        get_network_view: function(net) {
1344
            return this.network_views[net.id];
1345
        },
1346

    
1347
        remove_net: function(net) {
1348
            if (this.network_added(net)) {
1349
                var view = this.get_network_view(net);
1350
                if (view == this.public_network) {
1351
                  this.public_network.remove_network(net);
1352
                } else {
1353
                  view.remove();
1354
                }
1355
                delete this.network_views[net.id];
1356
            }
1357
        },
1358

    
1359
        __update_layout: function() {
1360
        }
1361
    });
1362

    
1363
})(this);