Revision 69dac1ba

b/snf-cyclades-app/synnefo/ui/static/snf/css/main.css
6517 6517
    font-size: 0.8em;
6518 6518
}
6519 6519

  
6520
.create-vm .network-select {
6521
  height: 278px;
6522
  overflow-y: scroll;
6523
  padding-right: 10px;
6524
}
6525

  
6520 6526
.vm-connect .connect-cont {
6521 6527
    margin-bottom: 20px;
6522 6528
    border-bottom: 1px solid #A1C8DB;
......
7422 7428
.steps-container .floating-ips .collection {
7423 7429
}
7424 7430

  
7431
.ip-port-view .title {
7432
  font-weight: normal !important;
7433
}
7434

  
7435
.pane-view .title.floating-ip {
7436
  font-weight: bold !important;
7437
}
7438

  
7425 7439
.items-list.floating-ips {
7426 7440
  margin-top: -5px;
7427 7441
}
b/snf-cyclades-app/synnefo/ui/static/snf/js/models.js
163 163
                this.trigger("change:" + attr_name, obj);
164 164
              } else {
165 165
                var self = this;
166
                var retry = window.setInterval(function(){
167
                  var obj = store.get(val);
168
                  if (obj) {
169
                    data[key] = obj;
170
                    self.set(data, {silent:true})
171
                    self.trigger("change:" + attr_name, obj);
172
                    clearInterval(retry);
173
                  }
174
                }, 500);
166
                var retry_to_resolve = function(store, val, key) {
167
                  var retries = 0;
168
                  var retry = window.setInterval(function(){
169
                    retries++;
170
                    if (retries > 200) {
171
                      clearInterval(retry);
172
                    }
173
                    var obj = store.get(val);
174
                    if (obj) {
175
                      data[key] = obj;
176
                      self.set(data, {silent:false});
177
                      clearInterval(retry);
178
                    }
179
                  }, 500);
180
                  return retry
181
                }
182
                retry_to_resolve(store, val, key);
175 183
              }
176 184
            }
177 185
            
178 186
            var self = this;
179
            this.bind('change:' + attr, function(model) {
180
              resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
181
            }, this);
187
            function init_bindings(instance, store, key, attr, attr_resolver) {
188
              instance.bind('change:' + attr, function(model) {
189
                resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
190
              }, this);
182 191

  
183
            this.bind('add', function(model) {
184
              resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
185
            }, this);
192
              instance.bind('add', function(model) {
193
                resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
194
              }, this);
195
            }
196

  
197
            init_bindings(this, store, key, attr, attr_resolver);
186 198
            resolve_related_instance.call(this, store, key, attr_resolver(this, attr));
187 199
          }, this);
188 200
        },
......
317 329
        initialize: function() {
318 330
            models.Collection.__super__.initialize.apply(this, arguments);
319 331
            this.api_call = _.bind(this.api.call, this);
332
            if (this.sortFields) {
333
              _.each(this.sortFields, function(f) {
334
                this.bind("change:" + f, _.bind(this.resort, this));
335
              }, this);
336
            }
337
        },
338
          
339
        resort: function() {
340
          this.sort();
320 341
        },
321 342

  
322 343
        url: function(options, method) {
......
1024 1045
          return _.contains(["ACTIVE", "STOPPED"], this.get("status"))
1025 1046
        },
1026 1047

  
1048
        can_disconnect: function() {
1049
          return _.contains(["ACTIVE", "STOPPED"], this.get("status"))
1050
        },
1051

  
1027 1052
        can_resize: function() {
1028 1053
          return this.get('status') == 'STOPPED';
1029 1054
        },
......
1325 1350
        },
1326 1351
      
1327 1352
        connect_floating_ip: function(ip, cb) {
1353
          this.set({'status': 'CONNECTING'});
1328 1354
          synnefo.storage.ports.create({
1329 1355
            port: {
1330 1356
              network_id: ip.get('floating_network_id'),
......
1332 1358
              fixed_ips: [{'ip_address': ip.get('floating_ip_address')}]
1333 1359
            }
1334 1360
          }, {complete: cb, skip_api_error: false})
1335
          // TODO: Implement
1336 1361
        },
1337 1362

  
1338 1363
        // action helper
b/snf-cyclades-app/synnefo/ui/static/snf/js/neutron.js
414 414

  
415 415
      disconnect: function(cb) {
416 416
        var network = this.get('network');
417
        var vm = this.get('vm');
417 418
        network.pending_disconnects++;
418 419
        network.update_connecting_status();
419 420
        var success = _.bind(function() {
421
          if (vm) {
422
            vm.set({'status': 'DISCONNECTING'});
423
          }
420 424
          this.set({'status': 'DISCONNECTING'});
421 425
          cb();
422 426
        }, this);
......
472 476
          if (vm && vm.get("task_state")) { return false }
473 477
          if (vm && vm.in_error_state()) { return false }
474 478
          var status_ok = _.contains(['ACTIVE', 'CONNECTED'], this.get('status'))
475
          return status_ok
479
          var vm_status_ok = vm.can_disconnect();
480
          return status_ok && vm_status_ok;
476 481
        }]
477 482
      },
478 483

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_ips_view.js
94 94
        'CONNECTED': 'status-active',
95 95
        'ACTIVE': 'status-active',
96 96
        'CONNECTING': 'status-progress',
97
        'DISCONNECTING': 'status-inactive',
97
        'DISCONNECTING': 'status-progress',
98 98
        'DOWN': 'status-inactive',
99 99
        'DISCONNECTED': 'status-inactive',
100 100
        'UP': 'status-active',
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_networks_view.js
795 795
      tpl: '#networks-select-floating-ips-tpl',
796 796
      model_view_cls: views.NetworkSelectFloatingIpView,
797 797

  
798
      select_if_available: function() {
799
        var selected = false;
800
        if (this._subviews[0]) {
801
          this._subviews[0].select();
802
        }
803
      },
804

  
805 798
      deselect_all: function() {
806 799
        this.each_ip_view(function(v) { v.deselect() });
807 800
      },
......
854 847
          this.hide_parent();
855 848
          return;
856 849
        }
850
        this.select_first();
857 851
        this.parent_view.item.addClass("selected");
858 852
        this.parent_view.input.attr("checked", true);
859 853
        this.parent_view.selected = true;
860 854
        this.show(true);
861
        this.select_if_available();
862 855
      },
863 856

  
864 857
      update_available: function() {
......
904 897
      },
905 898
      
906 899
      update_selected: function() {
900
        // reset missing entries
907 901
        _.each(this.selected_ips.length, function(ip) {
908 902
          if (!this.collection.get(ip.id)) {
909 903
            this.selected_ips = _.without(this.selected_ips, ip);
......
913 907
        if (this.selected_ips.length) {
914 908
          this.parent_view.input.attr("checked", true);
915 909
          this.parent_view.item.addClass("selected");
916
          this.parent_view.item.selected = true;
910
          this.parent_view.selected = true;
917 911
        } else {
918 912
          this.parent_view.input.attr("checked", false);
919 913
          this.parent_view.item.removeClass("selected");
920
          this.parent_view.item.selected = false;
914
          this.parent_view.selected = false;
921 915
        }
922 916
      },
923 917

  
......
955 949
          skip_api_error: true
956 950
        });
957 951
      },
952
      
953
      select_first: function() {
954
        if (this.selected_ips.length > 0) { return }
955
        if (this._subviews.length == 0) { return }
956
        this._subviews[0].select();
957
        if (!_.contains(this.selected_ips, this._subviews[0].model)) {
958
          this.selected_ips.push(this._subviews[0].model);
959
        }
960
      },
958 961

  
959 962
      post_add_model_view: function(view, model) {
960 963
        view.bind("change:select", this.handle_ip_select)
961 964
        if (!this.selected_ips.length && this._subviews.length == 1) {
962
          this._subviews[0].select();
963
          if (!_.contains(this.selected_ips, model)) {
964
            this.selected_ips.push(model);
965
          }
965
          this.select_first();
966 966
        }
967 967
      },
968 968

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_public_keys_view.js
304 304
        this.model.remove(function() {
305 305
            synnefo.storage.keys.fetch();
306 306
        });
307
      },
308

  
309
      post_hide: function() {
310
        views.PublicKeyView.__super__.post_hide.apply(this);
311
        if (this.content_visible) {
312
          this.toggle_content();
313
          this.content.hide();
314
        }
307 315
      }
308 316
    });
309 317
    
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_single_view.js
65 65
        
66 66
        var self = this;
67 67
        this.toggler.click(function() {
68
          if(self.toggler.parent().parent().hasClass("disabled")) {
69
            return;
70
          }
68 71
          self.toggle();
69 72
        });
70 73

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/views_ext.js
237 237
      
238 238
      update_quota: function() {
239 239
        var available = this.quota.get_available();
240
        if (available) {
240
        if (available > 0) {
241 241
          this.create_button.removeClass("disabled");
242 242
          this.create_button.attr("title", this.quota_limit_message || "Quota limit reached")
243 243
        } else {
......
277 277
        if (!view) { return }
278 278
        el = view.el;
279 279
        parent = this.parent_for_model(model);
280
        index = this.collection.indexOf(model);
280 281
        if (!parent.find(el).length) {
281
          index = this.collection.indexOf(model);
282 282
          anim = true;
283 283
          this.place_in_parent(parent, el, model, index, anim);
284 284
        }
285
        if (index != view.el.data('index')) {
286
          this.place_in_parent(parent, el, model, index, false);
287
        }
285 288
      },
286 289

  
287 290
      handle_collection_change: function() {
......
320 323
      },
321 324
      
322 325
      place_in_parent: function(parent, el, m, index, anim) {
323
        var place_func, place_func_context, position_found;
326
        var place_func, place_func_context, position_found, exists;
324 327

  
325 328
        _.each(parent.find(".model-item"), function(el) {
326 329
          var el = $(el);
b/snf-cyclades-app/synnefo/ui/templates/partials/ips.html
5 5
    <div class="inner clearfix main-content">
6 6
      <div class="model-logo vm-icon medium2 state1"
7 7
        data-rv-style="model.vm.status|vm_style"></div>
8
      <h5 class="title" data-rv-text="model.vm.name|truncate 50"></h5>
8
      <h3 class="title" data-rv-text="model.vm.name|truncate 40"></h3>
9 9
      <h5 class="subtitle">
10 10
        <span class="key" data-rv-show="model.mac_address">MAC:</span>
11 11
        <span class="value" data-rv-text="model.mac_address"></span>
......
21 21
      <div class="main-content-inner clearfix">
22 22
        <img class="logo" src="{{ SYNNEFO_IMAGES_URL }}internet.png" />
23 23
        <div class="entry inline" data-rv-class-connected="model.device_id">
24
          <h3 class="title">
24
          <h3 class="title floating-ip">
25 25
            <span data-rv-text="model.floating_ip_address">IP ADDRESS</span>
26 26
          </h3>
27 27
          <div data-rv-if="model.port_id" class="ports nested-model-list proxy inline">
b/snf-cyclades-app/synnefo/ui/templates/partials/networks.html
93 93
    <div class="border2"></div>
94 94
    <div class="inner clearfix main-content">
95 95
      <img class="model-logo" data-rv-src="model.vm.status|vm_logo_url" />
96
      <h5 class="title" data-rv-text="model.vm.name"></h5>
96
      <h5 class="title" data-rv-text="model.vm.name|truncate 35"></h5>
97 97
      <ul class="ip-addresses">
98 98
        <li data-rv-each-item="model.fixed_ips">
99 99
          <span data-rv-text="item:ip_address|ip_type" class="type"></span>
......
230 230
  <div class="collection">
231 231

  
232 232
    <div id="create-network" class="create-button">
233
      <a href="#">{% trans "New network +" %}</a>
233
      <a href="#">{% trans "New Network +" %}</a>
234 234
    </div>
235 235

  
236 236
    <div class="empty-list hidden">
......
273 273
    <div class="checkbox">
274 274
      <input type="checkbox" data-rv-data-id="model.id" />
275 275
    </div>
276
    <div class="ico"><img data-rv-src="model.is_public|get_network_icon" /></div>
276
    <div class="ico">
277
      <img data-rv-src="model.is_public|get_network_icon" />
278
    </div>
277 279
    <div class="name">
278 280
      <span class="" data-rv-text="model.name"></span>
279 281
      <span class="no-available hidden">{% trans "No IPs available" %}</span>
......
290 292
  <div class="select-item private-network clearfix">
291 293
    <div class="checkbox"><input type="checkbox" data-rv-data-id="model.id"></div>
292 294
    <div class="ico"><img data-rv-src="model.is_public|get_network_icon" /></div>
293
    <div class="name"><span class="" data-rv-text="model.name|truncate 50"></span></div>
295
    <div class="name"><span class="" data-rv-text="model.name|truncate 45"></span></div>
294 296
    <div class="cidr"><span class="" data-rv-text="model.subnet.cidr"></span></div>
295 297
  </div>
296 298
</div>
b/snf-cyclades-app/synnefo/ui/templates/partials/public_keys.html
90 90
  <div class="collection">
91 91

  
92 92
    <div id="create-keypair" class="create-button">
93
      <a href="#">{% trans "New public key +" %}</a>
93
      <a href="#">{% trans "New Keypair +" %}</a>
94 94
    </div>
95 95

  
96 96
    <div class="empty-list hidden">

Also available in: Unified diff