Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_icon_view.js @ c26afad6

History | View | Annotate | Download (27.3 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(e){
124
                e.preventDefault();
125
                snf.ui.main.show_vm_details(this.vm);
126
            }, this))
127
        }
128
    
129
    })
130

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
545
            this.update_layout();
546
        },
547

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

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

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

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

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

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

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

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

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

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

    
643
        },
644

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

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

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

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

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

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

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

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

    
735
            return os;
736
        },
737

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

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

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

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

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

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

    
777
})(this);