Revision c68ad72e

b/snf-cyclades-app/synnefo/ui/static/snf/css/main.css
3246 3246
}
3247 3247

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

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

  
3273 3274
.machine .info-content.ips .ips {
......
3282 3283
}
3283 3284

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

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

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

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

  
......
7212 7212
.model-rename-view .rename-actions .btn.cancel:hover {
7213 7213
  background-image: url("../images/cancel-onhover.png"); 
7214 7214
}
7215

  
7216

  
7217
.select-item input {
7218
  cursor: pointer;
7219
}
7220

  
7221
.select-item {
7222
  font-size: 0.9em;
7223
  padding: 5px 4px;
7224
  margin-bottom: 3px;
7225
  background-color: #efefef;
7226
  cursor: pointer;
7227
}
7228

  
7229
.select-item.selected {
7230
  background-color: #4085A5;
7231
}
7232

  
7233
.select-item.selected * {
7234
  color: #fff;
7235
}
7236

  
7237
.items-list.floating-ips {
7238
  margin-top: -5px;
7239
}
7240

  
7241
.select-item.floating-ip.not-available {
7242
  background-image: none;
7243
}
7244

  
7245
.select-item.floating-ip.create {
7246
  padding-left: 34px;
7247
  margin-bottom: 5px;
7248
  background-image: url("../images/option-action-add-dark.png");
7249
  background-repeat: no-repeat;
7250
  background-position: 9px 7px;
7251
}
7252

  
7253
.select-item.floating-ip.selected * {
7254
  color: #222 !important;
7255
  font-weight: bold;
7256
}
7257

  
7258
.select-item.floating-ip {
7259
  border-left: 10px solid #efefef;
7260
  background-color: #ddd;
7261
  margin-bottom: 0;
7262
  border-bottom: 1px solid #efefef;
7263
}
7264

  
7265
.select-item.private-network .name {
7266
  float: left;
7267
  width: 50%;
7268
}
7269

  
7270
.select-item.private-network .cidr {
7271
  float: left;
7272
  width: 40%;
7273
}
7274

  
7275
.select-item .name {
7276
  float: left;
7277
  width: 90%;
7278
}
7279

  
7280
.select-item .ico {
7281
  float: left;
7282
  width: 5%;
7283
}
7284

  
7285
.select-item .checkbox {
7286
  float: left;
7287
  width: 5%;
7288
}
b/snf-cyclades-app/synnefo/ui/static/snf/js/neutron.js
104 104
      storage_attrs: {
105 105
        'subnets': ['subnets', 'subnet', function(model, attr) {
106 106
          var subnets = model.get(attr);
107
          if (subnets.length) { return subnets[0] }
107
          if (subnets && subnets.length) { return subnets[0] }
108 108
        }]
109 109
      },
110 110

  
......
216 216
          }
217 217
        });
218 218
        this.set({ports: this.ports});
219
        this.floating_ips = synnefo.storage.floating_ips;
220
        this.set({floating_ips: this.floating_ips});
221

  
222
        this.available_floating_ips = new Backbone.FilteredCollection(undefined, {
223
          collection: synnefo.storage.floating_ips,
224
          collectionFilter: function(m) {
225
            return !m.get('port_id');
226
          }
227
        });
228
        this.set({available_floating_ips: this.available_floating_ips});
219 229
      },
220 230

  
221 231
    })
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_create_view.js
1090 1090
          
1091 1091
          this.fetcher = undefined;
1092 1092
          if (this.update_collection) {
1093
            this.fetcher_params = [snf.config.update_interval, 
1094
                                  snf.config.update_interval_increase || 500,
1095
                                  snf.config.fast_interval || snf.config.update_interval/2, 
1096
                                  snf.config.update_interval_increase_after_calls || 4,
1097
                                  snf.config.update_interval_max || 20000,
1098
                                  true, 
1099
                                  {is_recurrent: true, update: true}];
1093
              this.fetcher_params = [snf.config.update_interval, 
1094
                    snf.config.update_interval_increase || 500,
1095
                    snf.config.fast_interval || snf.config.update_interval/2, 
1096
                    snf.config.update_interval_increase_after_calls || 4,
1097
                    snf.config.update_interval_max || 20000,
1098
                    true, 
1099
                    {is_recurrent: true, update: true}];
1100 1100
              this.fetcher = this.collection.get_fetcher.apply(this.collection, 
1101 1101
                                                _.clone(this.fetcher_params));
1102 1102
              this.fetcher.start();
......
1179 1179
        initialize: function() {
1180 1180
            views.CreateNetworkingView.__super__.initialize.apply(this, arguments);
1181 1181
            this.init_handlers();
1182
            this.ssh_list = this.$(".ssh ul");
1183 1182
            this.selected_keys = [];
1184

  
1185
            var self = this;
1186
            this.$(".create-ssh-key").click(function() {
1187
                var confirm_close = true;
1188
                if (confirm_close) {
1189
                    snf.ui.main.public_keys_view.show(self.parent);
1190
                } else {
1191
                }
1192
            });
1193

  
1183
            this.cont = this.$(".step-cont");
1194 1184
        },
1195 1185
        
1196 1186
        init_subviews: function() {
1197 1187
            var create_view = this.parent;
1198
            if (!this.ips_view) {
1199
              this.ips_view = new views.CreateColumnSelectListView({
1200
                collection: synnefo.storage.floating_ips,
1201
                extra_class: 'public-ips',
1202
                update_collection: true,
1203
                title: 'IP addresses <span class="create-ip-address"><a href="#">manage ip\'s</a></span>',
1204
                description: 'Select IP addresses to be assigned to the created machine.',
1205
                item_cls: views.CreateColumnIPOptionView,
1206
                empty_msg: 'No IP addresses available. <span><a href="">Create a new IP address.</a></span>',
1207
                select_first_as_default: true,
1208
                filter_items: function(model) { 
1209
                  return !(model.get('port_id'))
1210
                },
1211
                init_events: function() {
1212
                  var msg = this.$(".empty span a");
1213
                  this.$(".empty a").bind('click', function(e) {
1214
                      e.preventDefault();
1215
                      msg.text("Creating...");
1216
                      synnefo.storage.floating_ips.create({
1217
                        address:undefined, pool: undefined
1218
                      }, {
1219
                        error: function() {
1220
                          alert("Cannot create new ip address");
1221
                        },
1222
                        complete: function() {
1223
                          msg.text("Create a new IP address.");
1224
                          msg.show();
1225
                        },
1226
                        skip_api_error: true,
1227
                      })
1228
                  });
1229
                }
1230
              });
1231
              $(this.ips_view.el).appendTo(this.$(".personalize-conts"));
1232
            }
1233 1188
            if (!this.networks_view) {
1234
              this.networks_view = new views.CreateColumnSelectListView({
1235
                collection: synnefo.storage.networks,
1236
                extra_class: 'private-networks',
1237
                title: 'Private networks',
1238
                description: 'Select private networks to connect the created machine to. You can manage your private networks from the networks tab.',
1239
                item_cls: views.CreateColumnPrivateNetworkOptionView,
1240
                filter_items: function(model) { return !model.is_public() }
1189
              this.networks_view = new views.NetworkSelectView({
1190
                container: this.cont
1241 1191
              });
1242
              $(this.networks_view.el).appendTo(this.$(".personalize-conts"));
1192
              this.networks_view.hide(true);
1243 1193
            }
1244 1194
        },
1245 1195

  
......
1250 1200
            views.CreateNetworkingView.__super__.show.apply(this, arguments);
1251 1201
            this.init_subviews();
1252 1202
            this.update_layout();
1203
            this.networks_view.show(true);
1253 1204
        },
1254 1205
        
1206
        hide_step: function() {
1207
            this.networks_view && this.networks_view.hide(true);
1208
        },
1209

  
1255 1210
        update_layout: function() {
1256 1211
        },
1257 1212

  
......
1261 1216
        },
1262 1217
        
1263 1218
        get_selected_networks: function() {
1264
          if (!this.networks_view) { return [] }
1265
          return this.networks_view.get_selected();
1219
            if (!this.networks_view) { return [] }
1220
            return this.networks_view.get_selected_networks();
1266 1221
        },
1267 1222
        
1268 1223
        get_selected_addresses: function() {
1269
          if (!this.networks_view) { return [] }
1270
          return this.ips_view.get_selected();
1224
            if (!this.networks_view) { return [] }
1225
            return this.networks_view.get_selected_floating_ips();
1271 1226
        },
1272 1227

  
1273 1228
        get: function() {
......
1278 1233
        },
1279 1234

  
1280 1235
        remove: function() {
1281
          if (this.ips_view) {
1282
            this.ips_view.remove();
1283
            delete this.ips_view;
1284
          }
1285
          
1286 1236
          if (this.networks_view) {
1287 1237
            this.networks_view.remove();
1288 1238
            delete this.networks_view;
......
1513 1463
            }
1514 1464
            _.each(ips, _.bind(function(ip) {
1515 1465
                var el = this.make("li", {'class':'selected-ip-address'}, 
1516
                                  ip.get('ip'));
1466
                                  ip.get('floating_ip_address'));
1517 1467
                this.ip_addresses.append(el);
1518 1468
            }, this))
1519 1469

  
......
1725 1675
                    extra['personality'] = _.flatten(personality);
1726 1676
                }
1727 1677
                
1728
                extra['networks'] = _.map(data.networks, function(n) { return n.get('id') });
1729
                extra['floating_ips'] = _.map(data.addresses, function(ip) { return ip.get('ip') });
1678
                extra['networks'] = [];
1679
                _.each(data.networks, function(n) {
1680
                  extra.networks.push({'uuid': n.get('id')})
1681
                });
1682
                _.each(data.ips, function(ip) {
1683
                  extra.networks.push({
1684
                    'uuid': ip.get('network').get('id'),
1685
                    'fixed_ip': ip.get('floating_ip_address')
1686
                  });
1687
                });
1688

  
1689
                _.map(data.networks, function(n) { return n.get('id') });
1730 1690
                storage.vms.create(data.name, data.image, data.flavor, 
1731 1691
                                   meta, extra, _.bind(function(data){
1732 1692
                    _.each(data.addresses, function(ip) {
......
1799 1759
            // FIXME: this shouldn't be here
1800 1760
            // but since we are not calling step.hide this should work
1801 1761
            this.steps[1].image_details.hide();
1802

  
1762
            
1763
            this.current_view && this.current_view.hide_step && this.current_view.hide_step();
1803 1764
            this.current_view = this.steps[step];
1804 1765
            this.update_controls();
1805 1766

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_ips_view.js
155 155
      handle_create_click: function() {
156 156
        network = synnefo.storage.networks.get_floating_ips_network();
157 157
        this.collection.create({
158
          floatingip: {
159
            floating_network_id: network.id
160
          }
158
          floatingip: {}
161 159
        }, 
162 160
        {
163 161
          complete: _.bind(function() {
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_networks_view.js
679 679
            } else {
680 680
              this.set_subtitle(subtitle);
681 681
            }
682

  
683 682
            this.vms = vms;
684 683
            this.selected = selected;
685 684
            this.cb = callback;
......
692 691
            this.cb(this.get_selected());
693 692
        }
694 693
    });
694
    
695
    views.NetworkSelectModelView = views.ext.ModelView.extend({
696
      select: function() {
697
        if (!this.delegate_input) {
698
          this.input.attr("checked", true);
699
          this.item.addClass("selected");
700
        }
701
        this.selected = true;
702
        this.trigger("change:select", this, this.selected);
703
      },
704

  
705
      deselect: function() {
706
        if (!this.delegate_input) {
707
          this.input.attr("checked", false);
708
          this.item.removeClass("selected");
709
        }
710
        this.selected = false;
711
        this.trigger("change:select", this, this.selected);
712
      },
713
      
714
      toggle_select: function() {
715
        if (this.selected) { 
716
          this.deselect();
717
        } else {
718
          this.select();
719
        }
720
      },
721

  
722
      post_init_element: function() {
723
        this.input = $(this.$("input").get(0));
724
        this.item = $(this.$(".select-item").get(0));
725
        this.delegate_input = this.model.get('noselect');
726
        this.deselect();
727

  
728
        var self = this;
729
        if (self.model.get('forced')) {
730
          this.select();
731
          this.input.attr("disabled", true);
732
          $(this.el).attr('title', this.forced_title);
733
          $(this.el).tooltip({
734
            'tipClass': 'tooltip', 
735
            'position': 'top center',
736
            'offset': [-5, 0]
737
          });
738
        }
739

  
740
        $(this.item).click(function(e) {
741
          if (self.model.get('forced')) { return }
742
          e.stopPropagation();
743
          e.preventDefault();
744
          self.toggle_select();
745
        });
746
        
747
        views.NetworkSelectModelView.__super__.post_init_element.apply(this,
748
                                                                       arguments);
749
      }
750
    });
751

  
752
    views.NetworkSelectNetworkTypeModelView = views.NetworkSelectModelView.extend({
753
      get_network_icon: function() {
754
        var ico = this.model.get('is_public') ? 'internet-small.png' : 'network-small.png';
755
        return synnefo.config.media_url + 'images/' + ico;
756
      },
757
      forced_title: 'You machine will be automatically connected ' +
758
                    'to this network.'
759
    });
760

  
761
    views.NetworkSelectPublicNetwork = views.NetworkSelectNetworkTypeModelView.extend({
762
      tpl: '#networks-select-public-item-tpl',
763
      classes: 'public-network',
764
      post_init_element: function() {
765
        views.NetworkSelectPublicNetwork.__super__.post_init_element.apply(this);
766
        //$(this.el).attr('title', 'Public network tooltip');
767
        //$(this.el).tooltip({
768
          //'tipClass': 'tooltip', 
769
          //'position': 'top center',
770
          //'offset': [-5, 0]
771
        //});
772

  
773
      }
774
    });
775

  
776
    views.NetworkSelectPrivateNetwork = views.NetworkSelectNetworkTypeModelView.extend({
777
      tpl: '#networks-select-private-item-tpl',
778
      classes: 'private-network'
779
    });
780
    
781
    views.NetworkSelectTypeView = views.ext.CollectionView.extend({});
782
    views.NetworkSelectPublicNetworks = views.NetworkSelectTypeView.extend({
783
      tpl: '#networks-select-public-tpl',
784
      model_view_cls: views.NetworkSelectPublicNetwork,
785
      get_floating_ips: function() {
786
        return _.map(this._subviews[1]._subviews[0].selected, function(m) {
787
          return m.id;
788
        });
789
      }
790
    });
791
    
792
    views.NetworkSelectFloatingIpView = views.NetworkSelectModelView.extend({
793
      tpl: '#networks-select-floating-ip-tpl'
794
    });
795

  
796
    views.NetworkSelectFloatingIpsView = views.ext.CollectionView.extend({
797
      tpl: '#networks-select-floating-ips-tpl',
798
      model_view_cls: views.NetworkSelectFloatingIpView,
799

  
800
      select_available: function() {
801
        var selected = false;
802
        this.each_ip_view(function(v) { 
803
          if (selected) { return }
804
          v.select();
805
          selected = true;
806
        });
807
      },
808

  
809
      deselect_all: function() {
810
        this.each_ip_view(function(v) { v.deselect() });
811
      },
812

  
813
      each_ip_view: function(cb) {
814
        _.each(this._subviews, function(view) {
815
          if (view instanceof views.NetworkSelectFloatingIpView) {
816
            cb(view);
817
          }
818
        })
819
      },
820

  
821
      post_init: function() {
822
        this.selected = [];
823
        var parent = this.parent_view;
824
        var self = this;
825
        this.handle_ip_select = _.bind(this.handle_ip_select, this);
826
        this.create = this.$(".floating-ip.create");
827
        parent.bind("change:select", function(selected) {
828
          if (parent.selected) {
829
            self.show(true);
830
            self.select_available();
831
          } else {
832
            self.deselect_all();
833
            self.hide(true);
834
          }
835
        });
836

  
837
        this.create.click(function() {
838
          self.create_ip();
839
        })
840
      },
841
      
842
      post_add_model_view: function(view) {
843
        view.bind("change:select", this.handle_ip_select)
844
      },
845

  
846
      post_remove_model_view: function(view) {
847
        view.unbind("change:select", this.handle_ip_select)
848
      },
849

  
850
      handle_create_error: function() {},
851

  
852
      create_ip: function() {
853
        synnefo.storage.floating_ips.create({floatingip:{}}, {
854
          error: _.bind(this.handle_create_error, this),
855
          skip_api_error: true
856
        });
857
      },
858

  
859
      handle_ip_select: function(view) {
860
        if (view.selected) {
861
          this.selected.push(view.model);
862
        } else {
863
          this.selected = _.without(this.selected, view.model);
864
        }
865
        this.update_selected();
866
      },
867
      
868
      update_selected: function() {
869
        var selected = this.selected.length;
870
        if (selected) {
871
          this.parent_view.input.attr("checked", true);
872
          this.parent_view.item.addClass("selected");
873
          $(this.parent_view.el).addClass("selected");
874
        } else {
875
          this.parent_view.input.attr("checked", false);
876
          this.parent_view.item.removeClass("selected");
877
          $(this.parent_view.el).removeClass("selected");
878
        }
879
      },
880

  
881
      post_show: function() {
882
        if (!this.parent_view.selected) {
883
          this.hide(true);
884
        }
885
      },
886

  
887
      get_floating_ips: function() {
888
        return this.selected;
889
      }
890
    });
891

  
892
    views.NetworkSelectPrivateNetworks = views.NetworkSelectTypeView.extend({
893
      tpl: '#networks-select-private-tpl',
894
      model_view_cls: views.NetworkSelectPrivateNetwork,
895
      get_networks: function() {
896
        return _.filter(_.map(this._subviews, function(view) {
897
          if (view.selected) { return view.model.id }
898
        }), function(id) { return id });
899
      }
900

  
901
    });
902

  
903
    views.NetworkSelectView = views.ext.ModelView.extend({
904
      rivets_view: true,
905
      tpl: '#networks-select-view-tpl',
906
      select_public: true,
907

  
908
      initialize: function(options) {
909
        this.quotas = synnefo.storage.quotas.get('cyclades.private_network');
910
        options = options || {};
911
        options.model = options.model || new models.Model();
912
        this.private_networks = new Backbone.FilteredCollection(undefined, {
913
          collection: synnefo.storage.networks,
914
          collectionFilter: function(m) {
915
            return !m.get('is_public')
916
        }});
917

  
918
        this.public_networks = new Backbone.Collection();
919

  
920
        // forced networks
921
        // TODO: check config
922
        this.forced = new models.networks.Network({
923
          name: 'Public IPv6 Network', 
924
          subnets: [],
925
          is_public: true,
926
          forced: true
927
        });
928
        this.public_networks.add(this.forced);
929

  
930
        // combined public
931
        this.combined_public = new models.networks.CombinedPublicNetwork();
932
        this.combined_public.set({noselect: true, name: 'Internet'});
933
        this.public_networks.add(this.combined_public);
934

  
935
        model_attrs = {
936
          public_collection: this.public_networks,
937
          private_collection: this.private_networks,
938
          floating_selected: true
939
        }
940

  
941
        options.model.set(model_attrs);
942
        this._configure(options);
943
        return views.NetworkSelectView.__super__.initialize.call(this, options);
944
      },
945

  
946
      get_selected_floating_ips: function() {
947
        var ips = [];
948
        _.each(this._subviews, function(view) {
949
          if (view.get_floating_ips) {
950
            ips = _.union(ips, view.get_floating_ips());
951
          }
952
        }, this);
953
        return _.filter(
954
          _.map(ips, function(ipid) { 
955
          return synnefo.storage.floating_ips.get(parseInt(ipid))
956
        }), function(ip) { console.log("IP", ip); return ip });
957
      },
958

  
959
      get_selected_networks: function() {
960
        var networks = [];
961
        _.each(this._subviews, function(view) {
962
          if (view.get_networks) {
963
            networks = _.union(networks, view.get_networks());
964
          }
965
        }, this);
966
        return _.filter(
967
          _.map(networks, function(netid) { 
968
          return synnefo.storage.networks.get(netid)
969
        }), function(net) { return net });
970
      }
971
    });
695 972
 
696 973
})(this);
b/snf-cyclades-app/synnefo/ui/templates/partials/networks.html
240 240
    </div>
241 241
  </div>
242 242
</div>
243

  
244
<div id="networks-select-floating-ip-tpl" class="hidden">
245
  <div class="select-item floating-ip clearfix">
246
    <div class="checkbox">
247
      <input type="checkbox" data-rv-data-id="model.id" />
248
    </div>
249
    <div class="name" data-rv-text="model.floating_ip_address"></div>
250
  </div>
251
</div>
252

  
253
<div id="networks-select-floating-ips-tpl" class="hidden">
254
  <div class="collection">
255
    <div class="empty-list hidden">{% trans "No ip addresses available" %}</div>
256
    <div class="items-list floating-ips clearfix">
257
    </div>
258
    <div class="create model-item select-item floating-ip">create...</div>
259
  </div>
260
</div>
261

  
262
<div id="networks-select-public-item-tpl" class="hidden">
263
  <div class="select-item clearfix">
264
    <div class="checkbox">
265
      <input type="checkbox" data-rv-data-id="model.id" />
266
    </div>
267
    <div class="ico"><img data-rv-src="model.is_public|get_network_icon" /></div>
268
    <div class="name"><span class="" data-rv-text="model.name"></span></div>
269
  </div>
270
  <div data-rv-show="model.is_public" class="floating-ips">
271
    <div data-rv-collection-view="model.available_floating_ips|NetworkSelectFloatingIpsView">
272
    </div>
273
  </div>
274
</div>
275

  
276
<div id="networks-select-private-item-tpl" class="hidden">
277
  <div class="select-item private-network clearfix">
278
    <div class="checkbox"><input type="checkbox" data-rv-data-id="model.id"></div>
279
    <div class="ico"><img data-rv-src="model.is_public|get_network_icon" /></div>
280
    <div class="name"><span class="" data-rv-text="model.name"></span></div>
281
    <div class="cidr"><span class="" data-rv-text="model.subnet.cidr"></span></div>
282
  </div>
283
</div>
284

  
285
<div id="networks-select-public-tpl" class="hidden">
286
  <div class="collection">
287
    <div class="items-list">
288
    </div>
289
  </div>
290
</div>
291

  
292
<div id="networks-select-private-tpl" class="hidden">
293
  <div class="collection">
294
    <div class="items-list">
295
    </div>
296
  </div>
297
</div>
298

  
299
<div id="networks-select-view-tpl" class="hidden list-cont">
300
  <h4>{% trans "Available networks" %}</h4>
301
  <p class="desc">Select the networks you want your machine to get connected to.</p>
302
  <div class="network-select">
303
    <div class="public-list" 
304
      data-rv-collection-view="model.public_collection|NetworkSelectPublicNetworks">
305
    </div>
306
    <div class="private-list" 
307
      data-rv-collection-view="model.private_collection|NetworkSelectPrivateNetworks">
308
    </div>
309
  </div>
310
</div>

Also available in: Unified diff