Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_icon_view.js @ 5a434360

History | View | Annotate | Download (27.2 kB)

1
;(function(root){
2

    
3
    // root
4
    var root = root;
5
    
6
    // setup namepsaces
7
    var snf = root.synnefo = root.synnefo || {};
8
    var models = snf.models = snf.models || {}
9
    var storage = snf.storage = snf.storage || {};
10
    var ui = snf.ui = snf.ui || {};
11
    var util = snf.util = snf.util || {};
12

    
13
    var views = snf.views = snf.views || {}
14

    
15
    // shortcuts
16
    var bb = root.Backbone;
17
    
18
    // handle extended info toggler
19
    views.VMActionErrorView = views.View.extend({
20
    
21
        initialize: function (vm, view) {
22
            this.vm = vm;
23
            this.view = view;
24
            this.vm_view = this.view.vm(vm);
25

    
26
            this.has_error = false;
27
            
28
            this.error = this.vm_view.find(".action-error");
29
            this.close = this.vm_view.find(".close-action-error");
30
            this.show_btn = this.vm_view.find(".show-action-error");
31

    
32
            this.init_handlers();
33
            this.update_layout();
34
        },
35

    
36
        init_handlers: function() {
37
            // action call failed notify the user
38
            this.vm.bind("action:fail", _.bind(function(args){
39
                if (this.vm.action_error) {
40
                    this.has_error = true;
41
                    var action = "undefined";
42
                    try {
43
                        action = _.last(args).error_params.extra_details['Action'];
44
                    } catch (err) {console.log(err)};
45
                    
46
                    this.error.find(".action").text(action);
47
                    this.error.show();
48
                }
49
            }, this));
50
            
51
            // show error overlay
52
            this.show_btn.click(_.bind(function() {
53
                if (this.vm.action_error) {
54
                    this.show_error_overlay(this.vm.action_error);
55
                }
56
                this.vm.reset_action_error();
57
            }, this));
58
            
59
            // user requests to forget about the error
60
            this.close.click(_.bind(_.bind(function() {
61
                this.error.hide();
62
                this.vm.reset_action_error();
63
            }, this)));
64
            
65
            // hide error message if action fail get reset
66
            this.vm.bind("action:fail:reset", _.bind(function(){
67
                this.error.hide();
68
            }, this));
69
        },
70

    
71
        show_error_overlay: function(args) {
72
            var args = util.parse_api_error.apply(util, args);
73
            
74
            // force logout if UNAUTHORIZED request arrives
75
            if (args.code == 401) { snf.ui.logout(); return };
76
            
77
            var error_entry = [args.ns, args.code, args.message, args.type, args.details, args];
78
            ui.main.error_view.show_error.apply(ui.main.error_view, error_entry);
79
        },
80

    
81
        update_layout: function() {
82
            if (this.vm.action_error) {
83
                this.error.show();
84
            }
85
        }
86
    });
87

    
88
    // handle extended info toggler
89
    views.IconInfoView = views.View.extend({
90
    
91
        initialize: function (vm, view) {
92
            this.vm = vm;
93
            this.view = view;
94
            this.vm_view = this.view.vm(vm);
95
            
96
            this.info_link = $(".toggler", this.vm_view);
97
            this.el = $("div.info-content", this.vm_view);
98
            this.toggler = $(".toggler", this.vm_view);
99
            this.label = $(".label", this.vm_view);
100

    
101
            this.set_handlers();
102
        },
103

    
104
        set_handlers: function() {
105
            this.info_link.click(_.bind(function(){
106
                this.el.slideToggle();
107
                this.view.vm(this.vm).toggleClass("light-background");
108

    
109
                if (this.toggler.hasClass("open")) {
110
                    this.toggler.removeClass("open");
111
                    this.vm.stop_stats_update();
112
                } else {
113
                    this.toggler.addClass("open");
114
                    this.view.details_views[this.vm.id].update_layout();
115
                    this.view.tags_views[this.vm.id].update_layout();
116
                    this.view.stats_views[this.vm.id].update_layout();
117
                }
118
                
119
                var self = this;
120
                window.setTimeout(function() {$(self.view).trigger("resize")}, 300);
121
            }, this));
122

    
123
            this.$(".stats-report").click(_.bind(function(){
124
                snf.ui.main.show_vm_details(this.vm);
125
            }, this))
126
        }
127
    
128
    })
129

    
130
    // rename handler view
131
    // only icon view contains rename capability
132
    views.IconRenameView = views.View.extend({
133
        
134
        initialize: function(vm, view) {
135
            this.vm = vm;
136
            this.view = view;
137
            // name container
138
            this.el = $('div#' + this.view.id_tpl + vm.id + " div.name").get(0);
139
            // name inline element
140
            this.name = this.$('span.name');
141
            // rename button
142
            this.rename = this.$('span.rename');
143
            // save button
144
            this.save = this.$('.save');
145
            // cancel rename button
146
            this.cancel = this.$('.cancel');
147
            // where to place the input field
148
            this.edit_cont = this.$(".namecontainer");
149
            // buttons container
150
            this.buttons = this.$(".editbuttons");
151
            // current state
152
            this.renaming = false;
153
            // init event handlers
154
            this.set_handlers();
155
            // paint
156
            this.update_layout();
157
            views.IconRenameView.__super__.initialize.call(this);
158
        },
159
        
160
        // update elements visibility/state
161
        update_layout: function() {
162
            // if in renaming state
163
            if (this.renaming) {
164
                // if name is hidden we are already in renaming state
165
                // dont do nothing
166
                if (this.name.is(":hidden")){return}
167
                
168
                // hide name element to make space for the 
169
                // text input
170
                this.name.hide();
171
                this.rename.hide();
172
                // show confirm/cancel buttons
173
                this.buttons.show();
174
                // create text element
175
                this.create_input();
176
            } else {
177
                // name is visible not in edit mode
178
                if (this.name.is(":visible")){return}
179

    
180
                this.name.show();
181
                this.rename.show();
182
                this.buttons.hide();
183
                this.remove_input();
184
            }
185
        },
186
        
187
        // create rename input field and set appropriate 
188
        // event handlers
189
        create_input: function() {
190
            var self = this;
191
            this.edit_cont.append('<input class="vm-rename nametextbox" type="text" />');
192
            this.$('input').val(this.vm.get('name'));
193
            // give edit focus
194
            this.$('input').focus();
195
            // handle enter press
196
            this.$('input').keypress(function(ev){
197
                if (ev.charCode == 13) {
198
                    self.submit();
199
                }
200
            })
201
        },
202
        
203
        // remove input element
204
        remove_input: function() {
205
            this.$('input').remove();
206
        },
207
        
208
        // initialize event handlers
209
        set_handlers: function() {
210
            var self = this;
211
            // start rename when rename button is pressed
212
            this.rename.click(function() {
213
                self.renaming = true;
214
                self.update_layout();
215
            });
216
            
217
            // double click on name
218
            $(this.el).dblclick(function() {
219
                self.renaming = true;
220
                self.update_layout();
221
            });
222

    
223
            // cancel rename
224
            this.cancel.click(function() {
225
                self.renaming = false;
226
                self.update_layout();
227
            })
228
            
229
            // apply the rename
230
            // TODO: check if name is equal than the previous value
231
            this.save.click(function() {
232
                self.submit();
233
            })
234
        },
235

    
236
        submit: function() {
237
            var value = _(self.$('input').val()).trim();
238
            if (value == "") { return };
239
            this.renaming = false;
240
            this.vm.rename(self.$('input').val());
241
            this.update_layout();
242
        }
243
    });
244
    
245
    // VM connect interaction view
246
    views.IconVMConnectView = views.View.extend({
247
        
248
        initialize: function(vm, view) {
249
            // parent view (single, icon, list)
250
            this.parent = view;
251
            this.vm = vm;
252
            this.el = view.vm(vm);
253
            this.set_handlers();
254
            views.IconVMConnectView.__super__.initialize.call(this);
255
        },
256
        
257
        // set the appropriate handlers
258
        set_handlers: function() {
259
            // setup connect handler on vm icon interaction
260
            var el = this.el;
261
            var vm = this.vm;
262

    
263
            // element that triggers the connect handler
264
            var connect = el.find("div.connect-arrow, .logo");
265
            // connect status handler
266
            var handler = _.bind(this.connect_handler, {vm:vm, el:el, view:this.parent});
267
            $(connect).bind({'mouseover': handler, 'mouseleave': handler, 
268
                            'mousedown': handler, 'mouseup': handler,
269
                            'click': handler });
270
            
271
            // setup connect arrow display handlers 
272
            // while hovering vm container
273
            el.bind("mouseover", function(){
274
                if (vm.is_connectable()) {
275
                    el.find(".connect-border").show();
276
                    el.find(".connect-arrow").show();
277
                    el.find(".logo").css({cursor:"pointer"});
278
                } else {
279
                    el.find(".connect-border").hide();
280
                    el.find(".connect-arrow").hide();
281
                    el.find(".logo").css({cursor: "default"});
282
                }
283
            }).bind("mouseleave", function(){
284
                el.find(".connect-border").hide();
285
                el.find(".connect-arrow").hide();
286
            });
287
        },
288
        
289
        // connect arrow interaction handlers
290
        // BEWARE, this function has different context
291
        // than the View object itself, see set_vm_handlers
292
        connect_handler: function(event) {
293
            // nothing to do if we cannot connect to the vm
294
            if (!this.vm.is_connectable()) {return}
295
            
296
            var logo = this.el.find(".logo");
297
            var arrow = this.el.find(".connect-arrow");
298
            var border = this.el.find(".connect-border");
299
            
300
            // clear icon states
301
            logo.removeClass('single-image-state1 single-image-state2 single-image-state3 single-image-state4');
302
            
303
            // append the appropriate state class
304
            switch (event.type) {
305
                case "mouseover":       
306
                    logo.addClass('single-image-state4');
307
                    arrow.addClass('border-hover');
308
                    break;
309
                
310
                case "mouseleave":
311
                    logo.addClass('single-image-state1');
312
                    arrow.removeClass('border-hover');
313
                    break;
314

    
315
                case "mouseup":
316
                    logo.addClass('single-image-state4');
317
                    this.view.connect_overlay.show(this.vm);
318
                    break;
319

    
320
                case "mousedown":
321
                    logo.addClass('single-image-state2');
322
                    break;
323

    
324
                case "click":
325
                    //logo.addCLass('single-image-state4');
326
                    //this.view.connect_to_console(vm);
327
                    this.view.connect_overlay.show(this.vm);
328
                    break;
329

    
330
                default:
331
                    ;
332
            }
333
        },
334
        
335
        update_layout: function() {
336
        }
337

    
338
    });
339
    
340
    // vm metadata subview for icon and single view
341
    views.VMTagsView = views.View.extend({
342
        view_id: 'vm_tags',
343
        // metadata container selector
344
        el_sel: '.vm-metadata',
345
        // metadata row template
346
        tag_tpl: '<span class="tag-item"><span class="key">{0}</span><span class="value">{1}</span></span>',
347
        // how many tags to show
348
        tag_limit: 4,
349
        // truncate options (because container has different size on icon/single views)
350
        tag_key_truncate: 7,
351
        tag_value_truncate: 15,
352

    
353
        initialize: function(vm, view, toggle, limit, tag_key_truncate, tag_value_truncate) {
354
            this.tag_limit = limit || this.tag_limit;
355

    
356
            this.tag_key_truncate = tag_key_truncate || this.tag_key_truncate;
357
            this.tag_value_truncate = tag_value_truncate || this.tag_value_truncate;
358

    
359
            // does the view toggles the metadata container (single view)
360
            this.toggle = toggle || false;
361
            // parent view
362
            this.parent = view;
363
            this.vm = vm;
364
            this.el = this.parent.vm(vm);
365
            this.view_id = this.view_id + "_" + vm.id;
366

    
367
            // link to raise the metadata manager overlay
368
            this.link = this.$('a.manage-metadata');
369

    
370
            views.VMTagsView.__super__.initialize.call(this);
371
            this.set_handlers();
372
            this.update_layout();
373
        },
374
        
375
        // set the appropriate handlers
376
        set_handlers: function() {
377
            var self = this;
378
            // show the metadata editor overlay
379
            this.link.click(_.bind(function(ev) {
380
                ev.preventDefault();
381
                this.parent.metadata_view.show(this.vm);
382
            }, this));
383

    
384
            // tags have show/hide control ? bind events for them
385
            var self = this;
386
            if (this.toggle) {
387
                $(this.el).find(".tags-header").click(_.bind(function(){
388
                    $(self.el).find(".tags-content").slideToggle(600);
389
                    var toggler = $(this.el).find(".tags-header .cont-toggler");
390
                    
391
                    if (toggler.hasClass("open")) {
392
                        toggler.removeClass("open");
393
                    } else {
394
                        toggler.addClass("open");
395
                    }
396
                }, this));
397
                $(self.el).find(".tags-content").hide();
398
            }
399
        },
400
        
401
        // update metadata container and data
402
        update_layout: function() {
403

    
404
            // api metadata object
405
            var meta =  this.vm.get_meta();
406

    
407
            var i = 0;
408
            var cont = $(this.el).find(".items");
409

    
410
            // clear existing items
411
            cont.find(".tag-item").remove();
412
            
413
            // create tag elements
414
            _.each(meta, function(value, key){
415
                // respect the limit
416
                if (i > this.tag_limit) {
417
                    return;
418
                }
419
                
420
                // create element
421
                var new_el = $(this.tag_tpl.format(util.truncate(key, this.tag_key_truncate), 
422
                                                 util.truncate(": " + value, this.tag_value_truncate)));
423

    
424
                // add title attributes, improve accesibility
425
                // truncated values
426
                new_el.find("span.key").attr("title", key);
427
                new_el.find("span.value").attr("title", value);
428

    
429
                cont.append(new_el);
430
            }, this);
431
        }
432
    });
433
    
434

    
435
    // stats subview for single/icon views
436
    views.VMStatsView = views.View.extend({
437

    
438
        initialize: function(vm, view, options) {
439
            if (!options) {options = {}};
440
            this.vm = vm;
441
            this.parent = view;
442
            this.sel = options.el || this.el_sel || ".lower";
443
            this.el = this.parent.vm(vm).find(this.sel);
444
            
445
            // elements shortcuts
446
            this.cpu_loading = this.el.find(".cpu-graph .stat-busy");
447
            this.cpu_error = this.el.find(".cpu-graph .stat-error");
448
            this.cpu_img = this.el.find(".cpu-graph .stat-img");
449
            this.net_loading = this.el.find(".network-graph .stat-busy");
450
            this.net_error = this.el.find(".network-graph .stat-error");
451
            this.net_img = this.el.find(".network-graph .stat-img");
452

    
453
            this.loading = this.el.find(".stat-busy");
454
            this.error = this.el.find(".stat-error");
455
            this.img = this.el.find(".stat-img");
456
            
457
            // initial state paremeters
458
            this.stats = this.vm.get("stats");
459

    
460
            // timeseries or bar images ?
461
            this.stats_type = options.stats_type || "bar";
462

    
463
            views.VMStatsView.__super__.initialize.apply(this, arguments);
464
            this.set_handlers();
465
            this.update_layout();
466

    
467
            this.net_loading.show();
468
            this.net_error.hide();
469
            this.cpu_loading.show();
470
            this.cpu_error.hide();
471

    
472
            this.net_img.hide();
473
            this.cpu_img.hide();
474
        },
475

    
476
        
477
        set_handlers: function() {
478
            // update view state when vm stats update gets triggered
479
            this.vm.bind("stats:update", _.bind(function(){
480
                // update the layout
481
                this.update_layout();
482
            }, this));
483
        },
484
        
485
        get_images: function (type) {
486
            if (type == "bar") {
487
                return {'cpu': this.stats.cpuBar, 'net': this.stats.netBar };
488
            } else {
489
                return {'cpu': this.stats.cpuTimeSeries, 'net': this.stats.netTimeSeries };
490
            }
491
        },
492

    
493
        update_layout: function() {
494
            if (!this.vm.stats_available) {
495
                this.loading.show();
496
                this.img.hide();
497
                this.error.hide();
498
            } else {
499
                this.loading.hide();
500
                this.stats = this.vm.get("stats");
501
                var images = this.get_images(this.stats_type);
502

    
503
                if (images.cpu) {
504
                    this.cpu_img.attr({src:images.cpu}).show();
505
                    this.cpu_error.hide();
506
                } else {
507
                    this.cpu_img.hide();
508
                    this.cpu_error.show();
509
                }
510

    
511
                if (images.net) {
512
                    this.net_img.attr({src:images.net}).show();
513
                    this.net_error.hide();
514
                } else {
515
                    this.net_img.hide();
516
                    this.net_error.show();
517
                }
518
            }
519
            $(window).trigger("resize");
520
        }
521
    });
522

    
523
    views.VMDetailsView = views.View.extend({
524
        view_id: "vm_details",
525
        el_sel: '.vm-details',
526
        
527

    
528
        selectors: {
529
            'cpu': '.cpu-data',
530
            'ram': '.ram-data',
531
            'disk': '.disk-data',
532
            'image_name': '.image-data',
533
            'image_size': '.image-size-data'
534
        },
535

    
536
        initialize: function(vm, view) {
537
            this.parent = view;
538
            this.vm = vm;
539
            this.el = $(this.parent.vm(vm)).find(this.el_sel).get(0);
540
            this.view_id = "vm_{0}_details".format(vm.id);
541
            
542
            views.VMDetailsView.__super__.initialize.call(this);
543

    
544
            this.update_layout();
545
        },
546

    
547
        update_layout: function() {
548
            if (!this.visible() && this.parent.details_hidden) { return };
549

    
550
            var image = this.vm.get_image();
551
            var flavor = this.vm.get_flavor();
552
            if (!flavor || !image) {
553
                return;
554
            }
555

    
556
            this.sel('image_name').text(util.truncate(image.get('name'), 13)).attr("title", image.get('name'));
557
            this.sel('image_size').text(image.get_readable_size()).attr('title', image.get_readable_size());
558

    
559
            this.sel('cpu').text(flavor.get('cpu'));
560
            this.sel('ram').text(flavor.get('ram'));
561
            this.sel('disk').text(flavor.get('disk'));
562

    
563
            this.parent.tags_views[this.vm.id].update_layout();
564
            this.parent.stats_views[this.vm.id].update_layout();
565
            
566
            if (this.parent.details_hidden) {
567
                this.vm.start_stats_update(true);
568
            }
569
        }
570
    });
571
    
572
    // VMs icon view
573
    views.IconView = views.VMListView.extend({
574
        
575
        // view id (this could be used to identify 
576
        // the view object from global context
577
        view_id: 'vm_icon',
578
        
579
        details_hidden: true,
580

    
581
        el: '#machinesview-icon',
582
        id_tpl: 'icon-vm-',
583

    
584
        selectors: {
585
            'vms': '.machine-container',
586
            'vm': '#icon-vm-',
587
            'view': '#machinesview-icon',
588
            'tpl': '#machinesview-icon.standard #machine-container-template',
589
            'spinner': '.large-spinner',
590
            'vm_spinner': '#icon-vm-{0} .state .spinner',
591
            'vm_wave': '#icon-vm-{0} .wave',
592
            'vm_cont_active': '#machinesview-icon.standard .running',
593
            'vm_cont_terminated': '#machinesview-icon.standard .terminated'
594
        },
595
            
596
        reset: function() {},
597
        // overload show function
598
        show_view: function() {
599
            $(this.el).show();
600
            this.__update_layout();
601
        },
602

    
603
        post_update_vm: function(vm) {
604
        },
605

    
606
        // identify vm model instance id based on DOM element
607
        vm_id_for_element: function(el) {
608
            return el.attr('id').replace("icon-vm-","");
609
        },
610
        
611
        // set generic view handlers
612
        set_handlers: function() {
613
        },  
614
        
615
        // stuff to do when a new vm has been created.
616
        // - create vm subviews
617
        post_add: function(vm) {
618
            // rename views index
619
            this.rename_views = this.rename_views || {};
620
            this.stats_views = this.stats_views || {};
621
            this.connect_views = this.connect_views || {};
622
            this.tags_views = this.tags_views || {};
623
            this.details_views = this.details_views || {};
624
            this.info_views = this.info_views || {};
625
            this.action_error_views = this.action_error_views || {};
626
            this.action_views = this.action_views || {};
627

    
628
            this.action_views[vm.id] = new views.VMActionsView(vm, this, this.vm(vm), this.hide_actions);
629
            this.rename_views[vm.id] = new views.IconRenameView(vm, this);
630
            this.stats_views[vm.id] = new views.VMStatsView(vm, this, {el:'.vm-stats'});
631
            this.connect_views[vm.id] = new views.IconVMConnectView(vm, this);
632
            this.tags_views[vm.id] = new views.VMTagsView(vm, this);
633
            this.details_views[vm.id] = new views.VMDetailsView(vm, this);
634
            this.info_views[vm.id] = new views.IconInfoView(vm, this);
635
            this.action_error_views[vm.id] = new views.VMActionErrorView(vm, this);
636
        },
637
        
638
        // vm specific event handlers
639
        set_vm_handlers: function(vm) {
640
            var el = this.vm(vm);
641

    
642
        },
643

    
644
        check_terminated_is_empty: function() {
645
            // hide/show terminated container
646
            if (this.$(".terminated .machine-container").length == 0) {
647
                this.$(".terminated").hide()
648
            } else {
649
                this.$(".terminated").show()
650
            }
651

    
652
            $(window).trigger("resize");
653
        },
654
        
655
        // generic stuff to do on each view update
656
        // called once after each vm has been updated
657
        update_layout: function() {
658
            // TODO: why do we do this ??
659
            if (storage.vms.models.length > 0) {
660
                this.$(".running").removeClass("disabled");
661
            } else {
662
                this.$(".running").addClass("disabled");
663
            }
664
            
665
            this.check_terminated_is_empty();
666
    
667
            // FIXME: code from old js api
668
            this.$("div.separator").show();
669
            this.$("div.machine-container:last-child").find("div.separator").hide();
670
            fix_v6_addresses();
671
        },
672

    
673
        // update vm details
674
        update_details: function(vm) {
675
            var el = this.vm(vm);
676
            // truncate name
677
            el.find("span.name").text(util.truncate(vm.get("name"), 40));
678
            // set ips
679
            el.find("span.ipv4-text").text(vm.get_addresses().ip4 || "not set");
680
            // TODO: fix ipv6 truncates and tooltip handler
681
            el.find("span.ipv6-text").text(vm.get_addresses().ip6 || "not set");
682
            // set the state (i18n ??)
683
            el.find("div.status").text(STATE_TEXTS[vm.state()]);
684
            // set state class
685
            el.find("div.state").removeClass().addClass(views.IconView.STATE_CLASSES[vm.state()].join(" "));
686
            // os icon
687
            el.find("div.logo").css({'background-image': "url(" + this.get_vm_icon_path(vm, "medium") + ")"});
688
            
689
            el.removeClass("connectable");
690
            if (vm.is_connectable()) {
691
                el.addClass("connectable");
692
            }
693
            
694
            var status = vm.get("status");
695
            var state = vm.get("state");
696

    
697
            if (status == 'BUILD') {
698
                // update bulding progress
699
                el.find("div.machine-ips").hide();
700
                el.find("div.build-progress").show().text(vm.get('progress_message'));
701
            } else {
702
                // hide building progress
703
                el.find("div.machine-ips").show()
704
                el.find("div.build-progress").hide();
705
            }
706

    
707
            if (state == "DESTROY") {
708
                el.find("div.machine-ips").hide();
709
                el.find("div.build-progress").show().text("Terminating...");
710
            }
711

    
712
            icon_state = vm.is_active() ? "on" : "off";
713
            set_machine_os_image(el, "icon", icon_state, this.get_vm_icon_os(vm));
714
            
715
            // update subviews
716
            this.rename_views[vm.id].update_layout();
717
            this.connect_views[vm.id].update_layout();
718
            this.details_views[vm.id].update_layout();
719
        },
720

    
721
        post_remove_vm: function(vm) {
722
            this.check_terminated_is_empty();
723
            $(window).trigger("resize");
724
        },
725
            
726
        get_vm_icon_os: function(vm) {
727
            var os = vm.get_os();
728
            var icons = window.os_icons || views.IconView.VM_OS_ICONS;
729

    
730
            if (icons.indexOf(os) == -1) {
731
                os = "unknown";
732
            }
733

    
734
            return os;
735
        },
736

    
737
        // TODO: move to views.utils (the method and the VM_OS_ICON vars)
738
        get_vm_icon_path: function(vm, icon_type) {
739
            var os = vm.get_os();
740
            var icons = window.os_icons || views.IconView.VM_OS_ICONS;
741

    
742
            if (icons.indexOf(os) == -1) {
743
                os = "unknown";
744
            }
745

    
746
            return views.IconView.VM_OS_ICON_TPLS()[icon_type].format(os);
747
        }
748
    })
749

    
750
    views.IconView.VM_OS_ICON_TPLS = function() {
751
        return {
752
            "medium": snf.config.machines_icons_url + "medium/{0}-sprite.png"
753
        }
754
    }
755

    
756
    views.IconView.VM_OS_ICONS = window.os_icons || [];
757

    
758
    views.IconView.STATE_CLASSES = {
759
        'UNKNOWN':          ['state', 'error-state'],
760
        'BUILD':            ['state', 'build-state'],
761
        'REBOOT':           ['state', 'rebooting-state'],
762
        'STOPPED':          ['state', 'terminated-state'],
763
        'ACTIVE':           ['state', 'running-state'],
764
        'ERROR':            ['state', 'error-state'],
765
        'DELETED':           ['state', 'destroying-state'],
766
        'DESTROY':          ['state', 'destroying-state'],
767
        'BUILD_INIT':       ['state', 'build-state'], 
768
        'BUILD_COPY':       ['state', 'build-state'],
769
        'BUILD_FINAL':      ['state', 'build-state'],
770
        'SHUTDOWN':         ['state', 'shutting-state'],
771
        'START':            ['state', 'starting-state'],
772
        'CONNECT':          ['state', 'connecting-state'],
773
        'DISCONNECT':       ['state', 'disconnecting-state']
774
    };
775

    
776
})(this);