Revision ab3df8df

b/snf-cyclades-app/synnefo/ui/static/snf/css/main.css
7094 7094
.suspended .action-indicator {
7095 7095
  display: none !important;
7096 7096
}
7097

  
7098

  
7099
.trigger-resize {
7100
    background-image: url("../images/pencil-disabled.png");
7101
    background-position: right 2px;
7102
    background-repeat: no-repeat;
7103
    padding-right: 15px !important;
7104
    cursor: pointer;
7105
}
7106

  
7107
.can-resize .trigger-resize:hover {
7108
    text-decoration: underline;
7109
}
7110

  
7111
.can-resize .trigger-resize {
7112
    font-weight: bold;
7113
    background-image: url("../images/pencil.png");
7114
}
7115

  
7116
.vm-resize .flavor-options-cont {
7117
  float: none;
7118
  width: 100%;
7119
  margin: 0;
7120
  height: auto;
7121
}
7122

  
7123
.form-action.disabled {
7124
  background-color: #ddd;
7125
  color: #aaa;
7126
  border-color: #999;
7127
}
b/snf-cyclades-app/synnefo/ui/static/snf/js/models.js
1044 1044
            models.VM.__super__.unbind.apply(this, arguments);
1045 1045
        },
1046 1046

  
1047
        can_resize: function() {
1048
          return this.get('status') == 'STOPPED';
1049
        },
1050

  
1047 1051
        handle_stats_error: function() {
1048 1052
            stats = {};
1049 1053
            _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
......
1249 1253
            return flv;
1250 1254
        },
1251 1255

  
1256
        get_resize_flavors: function() {
1257
          var vm_flavor = this.get_flavor();
1258
          var flavors = synnefo.storage.flavors.filter(function(f){
1259
              return f.get('disk_template') ==
1260
              vm_flavor.get('disk_template') && f.get('disk') ==
1261
              vm_flavor.get('disk');
1262
          });
1263
          return flavors;
1264
        },
1265

  
1266
        get_flavor_quotas: function() {
1267
          var flavor = this.get_flavor();
1268
          return {
1269
            cpu: flavor.get('cpu') + 1, 
1270
            ram: flavor.get_ram_size() + 1, 
1271
            disk:flavor.get_disk_size() + 1
1272
          }
1273
        },
1274

  
1252 1275
        get_meta: function(key, deflt) {
1253 1276
            if (this.get('metadata') && this.get('metadata')) {
1254 1277
                if (!this.get('metadata')[key]) { return deflt }
......
1449 1472
                                         },  
1450 1473
                                         error, 'destroy', params);
1451 1474
                    break;
1475
                case 'resize':
1476
                    this.__make_api_call(this.get_action_url(), // vm actions url
1477
                                         "create", // create so that sync later uses POST to make the call
1478
                                         {resize: {flavorRef:params.flavor}}, // payload
1479
                                         function() {
1480
                                             success.apply(this, arguments)
1481
                                             snf.api.trigger("call");
1482
                                         },  
1483
                                         error, 'resize', params);
1484
                    break;
1485
                case 'destroy':
1486
                    this.__make_api_call(this.url(), // vm actions url
1487
                                         "delete", // create so that sync later uses POST to make the call
1488
                                         undefined, // payload
1489
                                         function() {
1490
                                             // set state after successful call
1491
                                             self.state('DESTROY');
1492
                                             success.apply(this, arguments);
1493
                                             synnefo.storage.quotas.get('cyclades.vm').decrease();
1494

  
1495
                                         },  
1496
                                         error, 'destroy', params);
1497
                    break;
1452 1498
                default:
1453 1499
                    throw "Invalid VM action ("+action_name+")";
1454 1500
            }
......
1902 1948
        comparator: function(flv) {
1903 1949
            return flv.get("disk") * flv.get("cpu") * flv.get("ram");
1904 1950
        },
1905

  
1906
        unavailable_values_for_quotas: function(quotas, flavors) {
1951
          
1952
        unavailable_values_for_quotas: function(quotas, flavors, extra) {
1907 1953
            var flavors = flavors || this.active();
1908 1954
            var index = {cpu:[], disk:[], ram:[]};
1955
            var extra = extra == undefined ? {cpu:0, disk:0, ram:0} : extra;
1909 1956
            
1910 1957
            _.each(flavors, function(el) {
1911 1958

  
1912
                var disk_available = quotas['disk'];
1959
                var disk_available = quotas['disk'] + extra.disk;
1913 1960
                var disk_size = el.get_disk_size();
1914 1961
                if (index.disk.indexOf(disk_size) == -1) {
1915 1962
                  var disk = el.disk_to_bytes();
......
1917 1964
                    index.disk.push(disk_size);
1918 1965
                  }
1919 1966
                }
1920

  
1921
                var ram_available = quotas['ram'];
1967
                
1968
                var ram_available = quotas['ram'] + extra.ram * 1024 * 1024;
1922 1969
                var ram_size = el.get_ram_size();
1923 1970
                if (index.ram.indexOf(ram_size) == -1) {
1924 1971
                  var ram = el.ram_to_bytes();
......
1928 1975
                }
1929 1976

  
1930 1977
                var cpu = el.get('cpu');
1931
                var cpu_available = quotas['cpu'];
1932
                if (index.ram.indexOf(cpu) == -1) {
1978
                var cpu_available = quotas['cpu'] + extra.cpu;
1979
                if (index.cpu.indexOf(cpu) == -1) {
1933 1980
                  if (cpu > cpu_available) {
1934 1981
                    index.cpu.push(el.get('cpu'))
1935 1982
                  }
......
1970 2017
        },
1971 2018
        
1972 2019
        get_data: function(lst) {
1973
            var data = {'cpu': [], 'mem':[], 'disk':[]};
2020
            var data = {'cpu': [], 'mem':[], 'disk':[], 'disk_template':[]};
1974 2021

  
1975 2022
            _.each(lst, function(flv) {
1976 2023
                if (data.cpu.indexOf(flv.get("cpu")) == -1) {
......
1982 2029
                if (data.disk.indexOf(flv.get("disk")) == -1) {
1983 2030
                    data.disk.push(flv.get("disk"));
1984 2031
                }
2032
                if (data.disk_template.indexOf(flv.get("disk_template")) == -1) {
2033
                    data.disk_template.push(flv.get("disk_template"));
2034
                }
1985 2035
            })
1986 2036
            
1987 2037
            return data;
......
2444 2494
            return this.get('resource').get('unit') == 'bytes';
2445 2495
        },
2446 2496
        
2447
        get_available: function() {
2448
            var value = this.get('limit') - this.get('usage');
2497
        get_available: function(active) {
2498
            suffix = '';
2499
            if (active) { suffix = '_active'}
2500
            var value = this.get('limit'+suffix) - this.get('usage'+suffix);
2449 2501
            if (value < 0) { return value }
2450 2502
            return value
2451 2503
        },
2452 2504

  
2453
        get_readable: function(key) {
2505
        get_readable: function(key, active) {
2454 2506
            var value;
2455 2507
            if (key == 'available') {
2456
                value = this.get_available();
2508
                value = this.get_available(active);
2457 2509
            } else {
2458 2510
                value = this.get(key)
2459 2511
            }
......
2469 2521
        api_type: 'accounts',
2470 2522
        path: 'quotas',
2471 2523
        parse: function(resp) {
2472
            return _.map(resp.system, function(value, key) {
2524
            filtered = _.map(resp.system, function(value, key) {
2473 2525
                var available = (value.limit - value.usage) || 0;
2526
                var available_active = available;
2527
                var keysplit = key.split(".");
2528
                var limit_active = value.limit;
2529
                var usage_active = value.usage;
2530
                keysplit[keysplit.length-1] = "active_" + keysplit[keysplit.length-1];
2531
                var activekey = keysplit.join(".");
2532
                var exists = resp.system[activekey];
2533
                if (exists) {
2534
                    available_active = exists.limit - exists.usage;
2535
                    limit_active = exists.limit;
2536
                    usage_active = exists.usage;
2537
                }
2474 2538
                return _.extend(value, {'name': key, 'id': key, 
2475 2539
                          'available': available,
2540
                          'available_active': available_active,
2541
                          'limit_active': limit_active,
2542
                          'usage_active': usage_active,
2476 2543
                          'resource': snf.storage.resources.get(key)});
2477
            })
2544
            });
2545
            return filtered;
2546
        },
2547
        
2548
        get_by_id: function(k) {
2549
          return this.filter(function(q) { return q.get('name') == k})[0]
2550
        },
2551

  
2552
        get_available_for_vm: function(active) {
2553
          var quotas = synnefo.storage.quotas;
2554
          var key = 'available';
2555
          if (active) { key = 'available_active'; }
2556
          var quota = {
2557
            'ram': quotas.get('cyclades.ram').get(key),
2558
            'cpu': quotas.get('cyclades.cpu').get(key),
2559
            'disk': quotas.get('cyclades.disk').get(key)
2560
          }
2561
          return quota;
2478 2562
        }
2479 2563
    })
2480 2564

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_create_view.js
677 677
              image_excluded = storage.flavors.unavailable_values_for_image(this.current_image);
678 678
            }
679 679

  
680
            quotas = this.get_vm_params_quotas();
681
            user_excluded = storage.flavors.unavailable_values_for_quotas(quotas);
680
            var quotas = synnefo.storage.quotas.get_available_for_vm({active: true});
681
            var user_excluded = storage.flavors.unavailable_values_for_quotas(quotas);
682 682

  
683 683
            unavailable.disk = user_excluded.disk.concat(image_excluded.disk);
684 684
            unavailable.ram = user_excluded.ram.concat(image_excluded.ram);
......
687 687
            this.unavailable_values = unavailable;
688 688
        },
689 689
        
690
        get_vm_params_quotas: function() {
691
          var quotas = synnefo.storage.quotas;
692
          var quota = {
693
            'ram': quotas.get('cyclades.ram').get('available'),
694
            'cpu': quotas.get('cyclades.cpu').get('available'),
695
            'disk': quotas.get('cyclades.disk').get('available')
696
          }
697
          return quota;
698
        },
699

  
700 690
        flavor_is_valid: function(flv) {
701 691
            if (!flv) { return false };
702 692

  
......
942 932

  
943 933
          var quotas = synnefo.storage.quotas;
944 934
          _.each(["disk", "ram", "cpu"], function(type) {
945
            var available_dsp = quotas.get('cyclades.'+type).get_readable('available');
946
            var available = quotas.get('cyclades.'+type).get('available');
935
            var active = true;
936
            var key = 'available';
937
            var available_dsp = quotas.get('cyclades.'+type).get_readable(key, active);
938
            var available = quotas.get('cyclades.'+type).get(key);
947 939
            var content = "({0} left)".format(available_dsp);
948 940
            if (available <= 0) { content = "(None left)" }
949 941
            
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_icon_view.js
622 622
            this.view_id = "vm_{0}_details".format(vm.id);
623 623
            
624 624
            views.VMDetailsView.__super__.initialize.call(this);
625

  
625
            
626
            this.resize_actions = this.$(".trigger-resize");
627
            this.init_handlers();
626 628
            this.update_layout();
627 629
        },
630
        
631
        init_handlers: function() {
632
          this.resize_actions.bind('click', _.bind(function(e){
633
              ui.main.vm_resize_view.show(this.vm);
634
          }, this));
635
        },
628 636

  
629 637
        update_layout: function() {
630 638
            if (!this.visible() && this.parent.details_hidden) { return };
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_main_view.js
536 536
            storage.vms.bind("change:status", _.bind(this.check_empty, this));
537 537
            storage.vms.bind("reset", _.bind(this.check_empty, this));
538 538
            storage.quotas.bind("change", _.bind(this.update_create_buttons_status, this));
539
            storage.quotas.bind("add", _.bind(this.update_create_buttons_status, this));
539 540
            
540 541
        },
541 542
        
......
714 715
                synnefo.glance.register();
715 716
            }
716 717
            this.error_view = new views.ErrorView();
718
            this.vm_resize_view = new views.VmResizeView();
717 719
            // api request error handling
718 720
            synnefo.api.bind("error", _.bind(this.handle_api_error, this));
719 721
            synnefo.api.bind("change:error_state", _.bind(this.handle_api_error_state, this));
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_vm_resize_view.js
1
// Copyright 2013 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 = snf.util || {};
46

  
47
    var views = snf.views = snf.views || {}
48

  
49
    // shortcuts
50
    var bb = root.Backbone;
51

  
52
    
53
    views.FlavorOptionsView = views.View.extend({
54

  
55
        choices_meta: {
56
            'cpu': {title: 'CPUs', description: 'Choose number of CPU cores'},
57
            'ram': {title: 'Memory size', description: 'Choose memory size'},
58
            'disk': {title: 'Disk size', description: 'Choose disk size'},
59
            'disk_template': {title: 'Storage', description: 'Select storage type'}
60
        },
61

  
62
        initialize: function(options) {
63
            views.FlavorOptionsView.__super__.initialize.apply(this);
64
            _.bindAll(this);
65
            this.$el = $(this.el);
66
            this.flavors = options.flavors || synnefo.storage.flavors.active();
67
            this.collection = options.collection || synnefo.storage.flavors;
68
            this.choices = options.choices || ['cpu', 'ram', 'disk', 
69
                                               'disk_template'];
70
            this.hidden_choices = options.hidden_choices || [];
71
            this.quotas = options.quotas || synnefo.storage.quotas;
72
            this.selected_flavor = options.selected_flavor || undefined;
73
            this.extra_quotas = options.extra_quotas || undefined;
74
            this.render();
75
            if (this.selected_flavor) { this.set_flavor(this.selected_flavor)}
76
        },
77

  
78
        render: function() {
79
            this.$el.empty();
80
            this.each_choice(function(choice) {
81
                var el = this[choice + '_el'] = $("<div>");
82
                el.addClass("flavor-options clearfix");
83
                el.addClass(choice);
84
                var title = $("<h4 class='clearfix'><span class='title'>" + 
85
                              "</span><span class='available'></span>" +
86
                              "<span class='desc'></span></h4>");
87
                el.append(title);
88
                el.find("span.title").text(this.choices_meta[choice].title);
89
                el.find("span.desc").text(this.choices_meta[choice].description);
90
                var ul = $("<ul/>");
91
                ul.addClass("flavors-"+choice+"-list flavor-opts-list clearfix");
92
                el.append(ul);
93
                this.$el.append(el);
94
                if (this.hidden_choices.indexOf(choice) > -1) {
95
                    el.hide();
96
                }
97
            });
98
            this.update_quota_left();
99
            this.fill();
100
            this.set_unavailable();
101
            this.init_handlers();
102
        },
103
        
104
        init_handlers: function() {
105
            this.$el.on('click', 'li.choice', _.bind(function(e) {
106
                var el = $(e.target).closest('li');
107
                if (el.hasClass('disabled')) { return }
108
                var choice = el.data('type');
109
                var value = el.data('value');
110
                var to_select = this.selected_flavor;
111
                if (to_select) {
112
                    var attrs = _.clone(to_select.attributes);
113
                    attrs[choice] = value;
114
                    to_select = this.collection.get_flavor(attrs.cpu, attrs.ram, 
115
                                                           attrs.disk, 
116
                                                           attrs.disk_template);
117
                }
118

  
119
                if (!to_select) {
120
                    var found = false;
121
                    _.each(this.flavors, _.bind(function(f){
122
                        if (found) { return }
123
                        if (f.get(choice) == value) {
124
                            found = true;
125
                            to_select = f;
126
                        }
127
                    }, this));
128
                }
129
                this.set_flavor(to_select);
130
            }, this));
131
        },
132
        
133
        update_quota_left: function() {
134
            this.each_choice(function(choice){
135
                var el = this[choice + '_el'].find(".available");
136
                el.removeClass("error");
137
                var quota = this.quotas.get('cyclades.'+choice);
138
                if (!quota) { return }
139
                var type = choice;
140
                var active = true;
141
                var key = 'available';
142
                var quotas = synnefo.storage.quotas;
143
                var available_dsp = quotas.get('cyclades.'+type).get_readable(key, active);
144
                var available = quotas.get('cyclades.'+type).get(key);
145
                var content = "({0} left)".format(available_dsp);
146
                if (available <= 0) { content = "(None left)"; el.addClass("error") }
147
                el.text(content);
148
            });
149
        },
150

  
151
        metric_for_choice: function(choice) {
152
            var map = {ram:'GB', cpu:'X', disk:'GB', disk_template:''};
153
            return map[choice] || '';
154
        },
155
        
156
        set_unavailable: function() {
157
            this.$el.find("li.choice").removeClass("disabled");
158
            var quotas = this.quotas.get_available_for_vm({'active': true});
159
            var extra_quotas = this.extra_quotas;
160
            var user_excluded = storage.flavors.unavailable_values_for_quotas(
161
              quotas, 
162
              storage.flavors.active());
163
            _.each(user_excluded, _.bind(function(values, key) {
164
                _.each(values, _.bind(function(value) {
165
                    var choice_el = this.select_choice(key, value);
166
                    choice_el.addClass("disabled");
167
                }, this));
168
            }, this));
169
        },
170

  
171
        select_choice: function(key, value) {
172
            return this.$el.find(".choice[data-type="+key+"][data-value="+value+"]");
173
        },
174

  
175
        fill: function(flavors) {
176
            var flavors = flavors || this.flavors;
177
            var data = this.collection.get_data(flavors);
178
            this.each_choice(function(choice) {
179
                var el = this[choice + '_el'].find("ul");
180
                el.empty();
181
                var key = choice;
182
                if (key == 'ram') { key = 'mem'}
183
                var values = data[key];
184
                if (!values) { return }
185
                _.each(values, _.bind(function(value) {
186
                    var entry = $("<li class='choice choice-" + choice + "' " +
187
                                  "data-value=" + value +
188
                                  " data-type=" + choice + ">" +
189
                                  "<span class='value'></span>" +
190
                                  "<span class='metric'></span></li>");
191
                    entry.find(".value").text(value);
192
                    entry.find(".metric").text(this.metric_for_choice(choice));
193
                    el.append(entry);
194
                    el.attr('value', value);
195
                }, this));
196
            });
197
        },
198

  
199
        set_flavor: function(flavor) {
200
            this.$el.find("li").removeClass("selected");
201
            if (!flavor) {this.selected_flavor = undefined; return}
202
            this.each_choice(function(choice){
203
                var el = this[choice + '_el'];
204
                var choice = el.find('.choice-'+choice+'[data-value='+flavor.get(choice)+']');
205
                choice.addClass("selected");
206
            });
207
            this.selected_flavor = flavor;
208
            this.trigger("flavor:select", this.selected_flavor);
209
        },
210

  
211
        each_choice: function(f) {
212
            return _.each(this.choices, _.bind(f, this));
213
        }
214
    });
215

  
216
    views.VmResizeView = views.Overlay.extend({
217
        
218
        view_id: "vm_resize_view",
219
        content_selector: "#vm-resize-overlay-content",
220
        css_class: 'overlay-vm-resize overlay-info',
221
        overlay_id: "vm-resize-overlay",
222

  
223
        subtitle: "",
224
        title: "Resize Machine",
225

  
226
        initialize: function(options) {
227
            this.flavors_view = undefined; 
228
            views.VmResizeView.__super__.initialize.apply(this);
229
            _.bindAll(this);
230
            this.submit = this.$(".form-action");
231
            this.pre_init_handlers();
232
        },
233

  
234
        pre_init_handlers: function() {
235
            this.submit.click(_.bind(function(){
236
                if (this.submit.hasClass("disabled")) {
237
                    return;
238
                };
239
                this.submit_resize(this.flavors_view.selected_flavor);
240
            }, this));
241
        },
242
        
243
        submit_resize: function(flv) {
244
            this.submit.addClass("in-progress");
245
            var complete = _.bind(function() {
246
              this.vm.set({'flavor': flv});
247
              this.vm.set({'flavorRef': flv.id});
248
              this.hide()
249
            }, this);
250
            this.vm.call("resize", complete, complete, {flavor:flv.id});
251
        },
252

  
253
        show: function(vm) {
254
            this.submit.removeClass("in-progress");
255
            this.vm = vm;
256
            this.vm.bind("change", this.handle_vm_change);
257
            if (this.flavors_view) {
258
                this.flavors_view.remove();
259
            }
260

  
261
            if (!this.vm.can_resize()) {
262
                this.$(".warning").show();
263
                this.submit.hide();
264
            } else {
265
                this.$(".warning").hide();
266
                this.submit.show();
267
                this.$(".flavor-options-inner-cont").append("<div>");
268
                this.flavors_view = new snf.views.FlavorOptionsView({
269
                    flavors:this.vm.get_resize_flavors(),
270
                    el: this.$(".flavor-options-inner-cont div"),
271
                    hidden_choices:['disk', 'disk_template'],
272
                    selected_flavor: this.vm.get_flavor(),
273
                    extra_quotas: this.vm.get_flavor_quotas()
274
                });
275
                this.flavors_view.bind("flavor:select", this.handle_flavor_select)
276
                this.submit.addClass("disabled");
277
            }
278
            views.VmResizeView.__super__.show.apply(this);
279
        },
280

  
281
        handle_flavor_select: function(flv) {
282
            if (flv.id == this.vm.get_flavor().id) {
283
                this.submit.addClass("disabled");
284
            } else {
285
                this.submit.removeClass("disabled");
286
            }
287
        },
288

  
289
        beforeOpen: function() {
290
            this.update_layout();
291
            this.init_handlers();
292
        },
293

  
294
        update_layout: function() {
295
            this.update_vm_details();
296
            this.render_choices();
297
        },
298
          
299
        render_choices: function() {
300
        },
301

  
302
        update_vm_details: function() {
303
            this.set_subtitle(this.vm.escape("name") + 
304
                              snf.ui.helpers.vm_icon_tag(this.vm, 
305
                                                         "small"));
306
        },
307

  
308
        handle_vm_change: function() {
309
          this.update_layout();
310
        },
311

  
312
        init_handlers: function() {
313
        },
314

  
315
        onClose: function() {
316
            this.editing = false;
317
            this.vm.unbind("change", this.handle_vm_change);
318
            this.vm = undefined;
319
        }
320
    });
321
    
322
})(this);
323

  
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_vms_base_view.js
326 326
            }
327 327
            
328 328
            var el = this.vm(vm);
329
            if (vm.can_resize()) {
330
              el.addClass("can-resize");
331
            } else {
332
              el.removeClass("can-resize");
333
            }
334

  
329 335
            if (vm.get('suspended')) {
330 336
              el.addClass("suspended");
331 337
            } else {
b/snf-cyclades-app/synnefo/ui/templates/home.html
73 73
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_feedback_view.js"></script>
74 74
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_create_view.js"></script>
75 75
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_connect_view.js"></script>
76
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_vm_resize_view.js"></script>
76 77
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_public_keys_view.js"></script>
77 78
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_custom_images.js"></script>
78 79

  
......
568 569
    <div id="user_custom_images" class="overlay-content overlay-content hidden">
569 570
        {% include "partials/custom_images.html" %}
570 571
    </div>
572
    {% include "partials/vm_resize.html" %}
571 573
    {% include "footer.html" %}
572 574

  
573 575
    <script>
......
678 680
            synnefo.ui.init();
679 681
            synnefo.ui.main.bind("ready", function(){
680 682
            });
683
              window.setTimeout(function(){
684
                $($(".machine-detail.ram.trigger-resize")[0]).click();
685
              }, 800);
681 686

  
682 687
        })
683 688
    </script>
b/snf-cyclades-app/synnefo/ui/templates/partials/machines_icon.html
54 54
                    <div class="metadata-container">
55 55
                        <div class="vm-details metadata-column">
56 56
                                <div class="flavor-details">
57
                                <span class="vm-detail"><span class="key">{% trans "CPUs" %}:</span> <span class="value"><span class="cpu-data">1</span></span></span>
58
                                <span class="vm-detail"><span class="key">{% trans "RAM" %}:</span><span class="value"><span class="ram-data">2048</span>MB</span></span>
59
                                <span class="vm-detail"><span class="key">{% trans "System Disk" %}:</span> <span class="value"><span class="disk-data">20</span>GB</span></span>
60
                            </div>
57
                                  <span class="vm-detail"><span class="key">
58
                                      {% trans "CPUs" %}:</span> <span
59
                                    class="value"><span
60
                                      class="cpu-data trigger-resize">1</span></span></span>
61
                                <span class="vm-detail"><span class="key">
62
                                    {% trans "RAM" %}:</span><span
63
                                    class="value trigger-resize"><span
64
                                      class="ram-data">2048</span>MB</span></span>
65
                                <span class="vm-detail"><span class="key">
66
                                    {% trans "System Disk" %}:</span> <span
67
                                    class="value"><span
68
                                      class="disk-data">20</span>GB</span></span>
69
                              </div>
61 70
                                <div class="image-details">
62 71
                                <span class="vm-detail"><span class="key">{% trans "Image" %}:</span> <span class="value"><span class="image-data">Debian</span></span></span>
63 72
                                <span class="vm-detail"><span class="key">{% trans "Image Size" %}:</span> <span class="value"><span class="image-size-data">2.3</span></span></span>
b/snf-cyclades-app/synnefo/ui/templates/partials/machines_single.html
39 39
                    <div class="machine-label ipv6">{% trans "Public IPv6" %}:</div>
40 40
                </div>
41 41
                <div class="machine-details">
42
                    <div class="machine-detail cpus">4</div>
43
                    <div class="machine-detail ram">2048</div>
42
                    <div class="machine-detail cpus trigger-resize">4</div>
43
                    <div class="machine-detail ram trigger-resize">2048</div>
44 44
                    <div class="machine-detail disk">100</div>
45 45
                    <div class="machine-detail image-name">windos_XP_blah_blah</div>
46 46
                    <div class="machine-detail image-size">2.3</div>
b/snf-cyclades-app/synnefo/ui/templates/partials/vm_resize.html
1
{% load i18n %}
2

  
3
<div id="vm-resize-overlay-content" class="hidden vm-resize content create-vm">
4
            <div class="warning hidden">
5
                {% blocktrans %}
6
                Machine resize is only available for machines in shutdown state.
7
                {% endblocktrans %}
8
            </div>
9
            <div class="flavor-options-cont content-cont clearfix">
10
                <div class="flavor-options-inner-cont clearfix"
11
                    id="create-vm-flavor-options">
12
                </div>
13
                <div class="form-actions plain clearfix">
14
                    <span class="form-action create">{% trans "resize machine" %}</span>
15
                </div>
16
            </div>
17
</div>
18

  

Also available in: Unified diff