Revision 365af933

b/snf-cyclades-app/synnefo/ui/static/snf/css/main.css
829 829
    
830 830
}
831 831

  
832
.icon .machine-container .info,
833
.icon .machine-container .ips {
832
.icon .machine-container .info {
834 833
    margin-top: 2px;
835 834
    height: 17px;
836 835
}
......
3228 3227
    display: none;
3229 3228
}
3230 3229

  
3230
.machine .info-content.ips .collection {
3231
  padding: 0;
3232
}
3233

  
3234
.machine .info-content.ips .ips .model-item .subnet {
3235
  padding-top: 2px;
3236
  width: 35%;
3237
  float: left;
3238
}
3239

  
3240
.machine .info-content.ips .ips .port-ip-item:last-child {
3241
  margin-bottom: 0;
3242
}
3243

  
3244
.machine .info-content.ips .ips .port-ip-item:hover {
3245
  background-color: #75A7BF;
3246
}
3247

  
3248
.machine .info-content.ips .ips .port-ip-item {
3249
  padding: 4px;
3250
  margin-bottom: 2px;
3251
}
3252

  
3253
.machine .info-content.ips .ips .model-item .ip {
3254
  padding-top: 2px;
3255
  width: 55%;
3256
  float: left;
3257
}
3258

  
3259
.machine .info-content.ips .ips .model-item .type {
3260
  float: left;
3261
  margin-right: 10px;
3262
  vertical-align: middle;
3263
  color: #fff;
3264
  background-color: #4085A5;
3265
  padding: 3px;
3266
}
3267

  
3268
.machine .info-content.ips .port {
3269
  width: 15%;
3270
  float: left;
3271
}
3272

  
3273
.machine .info-content.ips .ips {
3274
  width: 80%;
3275
  float: right;
3276
}
3277

  
3278
.machine .info-content.ips .port-item:last-child {
3279
  border-bottom: none;
3280
  padding-bottom: 0;
3281
  margin-bottom: 0;
3282
}
3283

  
3284
.machine .info-content.ips .port-item {
3285
  border-bottom: 1px solid #6F93A4;
3286
  padding: 5px 0;
3287
  margin-bottom: 5px;
3288
}
3289

  
3290
.machine .info-content.ips .port-item img {
3291
  float: left;
3292
  margin-top: 6px;
3293
  margin-right: 3%;
3294
}
3295

  
3296
.machine .info-content.ips .port-item .port {
3297
  font-weight: bold;
3298
  padding-top: 6px;
3299
}
3300

  
3301
.machine .info-content.ips {
3302
    background-color: #84B7D0;
3303
    padding: 5px 10px;
3304
    font-size: 0.6em;
3305
}
3306

  
3231 3307
.metadata-container {
3232 3308
    line-height: 12px;
3233 3309
    height: 85px;
......
3596 3672
    height: auto;
3597 3673
    padding-bottom: 5px;
3598 3674
    padding-top: 5px;
3599
    width: 300px;
3675
    width: 339px;
3600 3676
}
3601 3677

  
3602 3678
.single .column3 {
b/snf-cyclades-app/synnefo/ui/static/snf/js/models.js
690 690
        },
691 691

  
692 692
        initialize: function(params) {
693
            
693
            var self = this;
694
            this.ports = new Backbone.FilteredCollection(undefined, {
695
              collection: synnefo.storage.ports,
696
              collectionFilter: function(m) {
697
                return self.id == m.get('device_id')
698
            }});
699

  
694 700
            this.pending_firewalls = {};
695 701
            
696 702
            models.VM.__super__.initialize.apply(this, arguments);
697 703

  
704

  
698 705
            this.set({state: params.status || "ERROR"});
699 706
            this.log = new snf.logging.logger("VM " + this.id);
700 707
            this.pending_action = undefined;
b/snf-cyclades-app/synnefo/ui/static/snf/js/neutron.js
262 262
        return this.api_call(this.path, "create", params, complete, error, success);
263 263
      }
264 264
    });
265
    
266
    // dummy model/collection
267
    models.FixedIP = models.NetworkModel.extend({
268
      storage_attrs: {
269
        'subnet_id': ['subnets', 'subnet']
270
      }
271
    });
272
    models.FixedIPs = models.NetworkCollection.extend({
273
      model: models.FixedIP
274
    });
265 275

  
266 276
    models.Port = models.NetworkModel.extend({
267
      
268 277
      path: 'ports',
269

  
270 278
      initialize: function() {
271 279
        models.Port.__super__.initialize.apply(this, arguments);
280
        var ips = new models.FixedIPs();
281
        this.set({'ips': ips});
282
        this.bind('change:fixed_ips', function() {
283
          var ips = this.get('ips');
284
          //var ips = _.map(ips, function(ip) { ip.id = ip.a})
285
          this.update_ips()
286
        }, this);
287
        this.update_ips();
272 288
        this.set({'pending_firewall': null});
273 289
      },
274 290
      
291
      update_ips: function() {
292
        var ips = _.map(this.get('fixed_ips'), function(ip) {
293
          var type = "v4";
294
          if (ip.ip_address.indexOf(":") >= 0) {
295
            type = "v6";
296
          }
297
          ip.id = ip.ip_address;
298
          ip.type = type;
299
          ip.subnet_id = ip.subnet;
300
          delete ip.subnet;
301
          return ip;
302
        });
303
        this.get('ips').update(ips, {removeMissing: true});
304
      },
305

  
275 306
      model_actions: {
276 307
        'disconnect': [['status', 'network', 'vm'], function() {
277 308
          var network = this.get('network');
......
298 329
            return attachment.firewallProfile
299 330
          } 
300 331
        ],
301

  
332
        
302 333
        'firewall_running': [
303 334
          ['firewall_status', 'pending_firewall'], function(status, pending) {
304 335
              var pending = this.get('pending_firewall');
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_icon_view.js
127 127
            this.view = view;
128 128
            this.vm_view = this.view.vm(vm);
129 129
            
130
            this.info_link = $(".toggler", this.vm_view);
131
            this.info_el = $("div.info-content", this.vm_view);
132
            this.details_toggler = $(".toggler", this.vm_view);
130
            this.info_toggle = $(".cont-toggler-wrapper.info .toggler", this.vm_view);
131
            this.ips_toggle = $(".cont-toggler-wrapper.ips .toggler", this.vm_view);
132
            this.info_el = $("div.info-content.vm-info", this.vm_view);
133
            this.ips_el = $("div.info-content.ips", this.vm_view);
133 134
            this.label = $(".label", this.vm_view);
134 135

  
135 136
            this.set_handlers();
136 137
        },
137 138

  
138 139
        set_handlers: function() {
139
            this.info_link.click(_.bind(function(){
140
            this.info_toggle.click(_.bind(function(){
141
                this.ips_el.slideUp();
142
                this.ips_toggle.removeClass("open");
143

  
140 144
                this.info_el.slideToggle();
141 145
                this.view.vm(this.vm).toggleClass("light-background");
142 146

  
143
                if (this.details_toggler.hasClass("open")) {
144
                    this.details_toggler.removeClass("open");
147
                if (this.info_toggle.hasClass("open")) {
148
                    this.info_toggle.removeClass("open");
145 149
                    this.vm.stop_stats_update();
146 150
                } else {
147
                    this.details_toggler.addClass("open");
151
                    this.info_toggle.addClass("open");
148 152
                    this.view.details_views[this.vm.id].update_layout();
149 153
                    this.view.tags_views[this.vm.id].update_layout();
150 154
                    this.view.stats_views[this.vm.id].update_layout();
......
154 158
                window.setTimeout(function() {$(self.view).trigger("resize")}, 300);
155 159
            }, this));
156 160

  
161
            this.ips_toggle.click(_.bind(function(){
162
                this.info_el.slideUp();
163
                this.info_toggle.removeClass("open");
164

  
165
                this.ips_el.slideToggle();
166
                this.view.vm(this.vm).toggleClass("light-background");
167
                var self = this;
168
                if (this.ips_toggle.hasClass("open")) {
169
                    this.ips_toggle.removeClass("open");
170
                } else {
171
                    this.ips_toggle.addClass("open");
172
                }
173
                window.setTimeout(function() {$(self.view).trigger("resize")}, 300);
174
            }, this));
175

  
176

  
157 177
            this.$(".stats-report").click(_.bind(function(e){
158 178
                e.preventDefault();
159 179
                snf.ui.main.show_vm_details(this.vm);
......
416 436
                this.parent.metadata_view.show(this.vm);
417 437
            }, this));
418 438

  
419
            // tags have show/hide control ? bind events for them
439
            // tags/ips have show/hide control ? bind events for them
420 440
            var self = this;
421 441
            if (this.toggle) {
422 442
                $(this.el).find(".tags-header").click(_.bind(function(){
423 443
                    $(self.el).find(".tags-content").slideToggle(600);
424
                    var details_toggler = $(this.el).find(".tags-header .cont-toggler");
444

  
445
                    var details_toggler = $(this.el).find(".tags-header " +
446
                                                          ".cont-toggler.info");
447
                    var ips_toggler = $(this.el).find(".tags-header " +
448
                                                      ".cont-toggler.ips");
425 449
                    
426 450
                    if (details_toggler.hasClass("open")) {
427 451
                        details_toggler.removeClass("open");
428 452
                    } else {
429 453
                        details_toggler.addClass("open");
430 454
                    }
455

  
456
                    if (ips_toggler.hasClass("open")) {
457
                        ips_toggler.removeClass("open");
458
                    } else {
459
                        ips_toggler.addClass("open");
460
                    }
431 461
                }, this));
432 462
                $(self.el).find(".tags-content").hide();
433 463
            }
......
716 746
            this.info_views = this.info_views || {};
717 747
            this.action_error_views = this.action_error_views || {};
718 748
            this.action_views = this.action_views || {};
749
            this.ports_views = this.ports_views || {};
719 750

  
720 751
            this.action_views[vm.id] = new views.VMActionsView(vm, this, this.vm(vm), this.hide_actions);
721 752
            this.rename_views[vm.id] = new views.IconRenameView(vm, this);
......
723 754
            this.connect_views[vm.id] = new views.IconVMConnectView(vm, this);
724 755
            this.tags_views[vm.id] = new views.VMTagsView(vm, this);
725 756
            this.details_views[vm.id] = new views.VMDetailsView(vm, this);
726
            this.info_views[vm.id] = new views.IconInfoView(vm, this);
727 757
            this.action_error_views[vm.id] = new views.VMActionErrorView(vm, this);
758
            
759
            var ports_container = this.vm(vm).find(".machine-data");
760
            var ports_view = new views.VMPortListView({
761
              collection: vm.ports, 
762
              container: ports_container,
763
              parent: this
764
            });
765
            this.ports_views[vm.id] = ports_view
766
            ports_view.show();
767
            ports_view.el.hide();
768

  
769
            this.info_views[vm.id] = new views.IconInfoView(vm, this);
728 770
        },
729 771
        
730 772
        // vm specific event handlers
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_networks_view.js
382 382
      resolve_storage_object: function() {
383 383
        return this.collection
384 384
      },
385

  
386 385
      show_connect_vms_overlay: function() {
387 386
        this.parent_view.show_connect_vms_overlay();
388 387
      }
......
409 408
        this.ports_toggler.find(".cont-toggler").toggleClass("open");
410 409
        this.ports_visible = this.ports_toggler.find(".cont-toggler").hasClass("open");
411 410
      },
411
      
412
      get_network_icon: function() {
413
        var ico = this.model.get('is_public') ? 'internet.png' : 'network.png';
414
        return synnefo.config.media_url + 'images/' + ico;
415
      },
412 416

  
413 417
      post_hide: function() {
414 418
        views.NetworkView.__super__.post_hide.apply(this);
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_vms_base_view.js
734 734
        }
735 735
        snf.ui.trigger("error", { code:code, msg:msg, error:error, extra:extra || {} });
736 736
    };
737
    
738
    views.VMPortView = views.ext.ModelView.extend({
739
      tpl: '#vm-port-view-tpl',
740
      classes: 'port-item clearfix',
741
      get_network_name: function() {
742
        var network = this.model.get('network');
743
        var name = network && network.get('name');
744
        if (!name) {
745
          name = 'Internet'
746
        }
747
        name = synnefo.util.truncate(name, 18, '...');
748
        return name || 'Loading...';
749
      },
750

  
751
      get_network_icon: function() {
752
        var ico;
753
        var network = this.model.get('network');
754
        if (network) {
755
          ico = network.get('is_public') ? 'internet-small.png' : 'network-small.png';
756
        } else {
757
          ico = 'network-small.png';
758
        }
759
        return synnefo.config.media_url + 'images/' + ico;
760
      },
761
    });
762
    
763
    views.VMPortListView = views.ext.CollectionView.extend({
764
      tpl: '#vm-port-list-view-tpl',
765
      model_view_cls: views.VMPortView
766
    });
767

  
768
    views.VMPortIpView = views.ext.ModelView.extend({
769
      tpl: '#vm-port-ip-tpl'
770
    });
771

  
772
    views.VMPortIpsView = views.ext.CollectionView.extend({
773
      tpl: '#vm-port-ips-tpl',
774
      model_view_cls: views.VMPortIpView
775
    });
737 776

  
738 777
})(this);
b/snf-cyclades-app/synnefo/ui/static/snf/js/views_ext.js
26 26
    views.ext.View = views.View.extend({
27 27
      rivets_view: false,
28 28
      rivets: undefined,
29
      container: undefined,
30
      classes:'',
29 31

  
30 32
      storage_handlers: {},
31 33

  
32 34
      init: function() {},
33 35
      post_init: function() {},
34 36

  
35
      initialize: function() {
37
      initialize: function(options) {
38
        this.container = options && options.container;
36 39
        this._subviews = [];
37 40
        if (this.tpl) {
38 41
          this.el = $(this.tpl).clone().removeClass("hidden").removeAttr('id');
39 42
        }
40 43
        this.init.apply(this, arguments);
41 44
        this.post_init.apply(this, arguments);
45
        this.append_to_container();
46
        $(this.el).addClass(this.classes);
42 47
        _.bindAll(this);
43 48
      },
49
      
50
      append_to_container: function() {
51
        if (!this.container) { return }
52
        var cont = $(this.container);
53
        cont.append(this.el);
54
      },
44 55

  
45 56
      create_view: function(view_cls, options) {
46 57
        var options = _.extend({}, options);
......
384 395

  
385 396
    views.ext.ModelView = views.ext.View.extend({
386 397
      rivets_view: true,
387

  
398
      
388 399
      initialize: function() {
389 400
        views.ext.ModelView.__super__.initialize.apply(this, arguments);
390 401
        var actions = this.model.get('actions');
b/snf-cyclades-app/synnefo/ui/templates/partials/machines.html
31 31
{% include "partials/create_vm.html" %}
32 32
{% include "partials/manage_metadata.html" %}
33 33
{% include "partials/vm_connect.html" %}
34

  
35
<div id="vm-port-ips-tpl" class="hidden">
36
  <div class="collection fixed-ips-list">
37
    <div class="empty-list hidden">loading...</div>
38
    <div class="items-list clearfix"></div>
39
  </div>
40
</div>
41

  
42
<div id="vm-port-ip-tpl" class="hidden clearfix port-ip-item">
43
  <div class="type" data-rv-text="model.type"></div>
44
  <div class="ip" data-rv-text="model.ip_address"></div>
45
  <div class="cidr" data-rv-text="model.subnet.cidr"></div>
46
</div>
47

  
48
<div id="vm-port-view-tpl">
49
  <img data-rv-src="model.network.is_public|get_network_icon" />
50
  <div class="port" data-rv-text="model.network.name|get_network_name"></div>
51
  <div class="ips" data-rv-collection-view="model.ips|VMPortIpsView"></div>
52
</div>
53

  
54
<div id="vm-port-list-view-tpl" class="collection-list-view hidden info-content ips">
55
  <div class="collection">
56
    <div class="empty-list hidden">
57
      <p>{% trans "No IP addresses" %}</p>
58
    </div>
59
    <div class="items-list ports-list clearfix">
60
    </div>
61
  </div>
62
</div>
b/snf-cyclades-app/synnefo/ui/templates/partials/machines_icon.html
35 35
                                <span class="label">{% trans "info" %}</span>
36 36
                            </span>
37 37
                        </div>
38
                        <div class="cont-toggler-wrapper ips">
39
                          <span class="info-header cont-toggler toggler">
40
                            <span class="label">{% trans "ip addresses" %}</span>
41
                          </span>
42
                        </div>
38 43
                </div>
39 44
                <div class="state">
40 45
                    <div class="status">{% trans "Running" %}</div>
......
49 54
                    <img class="wave" style="display:none" src="{{ SYNNEFO_IMAGES_URL }}icons/indicators/medium/wave.gif" />
50 55
                </div>
51 56
                </div>
52
                <div class="info-content">
57
                <div class="info-content vm-info">
53 58
                    <div class="metadata-container">
54 59
                        <div class="vm-details metadata-column">
55 60
                                <div class="flavor-details">
b/snf-cyclades-app/synnefo/ui/templates/partials/networks.html
161 161
  <div class="clearfix">
162 162
    <div class="main-content clearfix">
163 163
      <div class="main-content-inner clearfix">
164
        <img class="logo" src="{{ SYNNEFO_IMAGES_URL }}internet.png" />
164
        <img class="logo" data-rv-src="model.is_public|get_network_icon" />
165 165
        <div class="entry">
166 166
          <div data-rv-show="model" 
167 167
               data-rv-model-view="model|ModelRenameView"></div>

Also available in: Unified diff