Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines_icon.html @ 1293d3ed

History | View | Annotate | Download (33.9 kB)

1
<!--
2
Copyright 2011 GRNET S.A. All rights reserved.
3

4
Redistribution and use in source and binary forms, with or
5
without modification, are permitted provided that the following
6
conditions are met:
7

8
  1. Redistributions of source code must retain the above
9
     copyright notice, this list of conditions and the following
10
     disclaimer.
11

12
  2. Redistributions in binary form must reproduce the above
13
     copyright notice, this list of conditions and the following
14
     disclaimer in the documentation and/or other materials
15
     provided with the distribution.
16

17
THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
POSSIBILITY OF SUCH DAMAGE.
29

30
The views and conclusions contained in the software and
31
documentation are those of the authors and should not be
32
interpreted as representing official policies, either expressed
33
or implied, of GRNET S.A.
34
-->
35

    
36
{% load i18n %}
37

    
38
<!-- the standard view -->
39
<div id="machinesview-icon" class="standard">
40
    <div class="machine-container" id="machine-container-template" style="display:none">
41
        <div class="machine" id="machine-template">
42
            <div class='connect-border'></div>
43
            <div class='connect-arrow'></div>
44
            <img class="logo" src="" />
45
            <div class="machine-details">
46
                <div href="#" class="name">
47
                    <h5 class="namecontainer editable">
48
                        <span class="name">node.name</span><span class="rename"></span>
49
                        <div class="editbuttons" style="display:none">
50
                            <div class="save"></div>
51
                            <div class="cancel"></div>
52
                        </div>
53
                    </h5>
54
                </div>
55
                <a href="#" class="ip">
56
                    <h5>{% trans "IP" %}: <span class="public">node.public_ip</span></h5>
57
                </a>
58
            </div>
59
            <div class="info">
60
                <div class="info-header">
61
                    <div class="info-label">{% trans "info" %}</div>
62
                    <div class="toggler down"></div>
63
                </div>
64
            </div>
65
            <div class="info-content">
66
                <div class="metadata-container">
67
                    <div class="vm-details metadata-column">
68
                        {% trans "CPUs" %}: <span class="cpu-data">1</span><br />
69
                        {% trans "RAM" %}: <span class="ram-data">2048</span> (MB)<br />
70
                        {% trans "System Disk" %}: <span class="disk-data">20</span> (GB) <br /><br />
71
                        {% trans "Image" %}: <span class="image-data">Debian</span><br />
72
                        {% trans "Image Size" %}: <span class="image-size-data">2.3</span> (GB)
73
                    </div>
74
                    <div class="vm-stats metadata-column">
75
                        {% trans "CPU" %} <img src="static/cpu-bar.png" class="metadata-bar" /><br />
76
                        {% trans "RAM" %} <img src="static/ram-bar.png" class="metadata-bar" /><br />
77
                        {% trans "S.Disk" %} <img src="static/cpu-bar.png" class="metadata-bar" /><br />
78
                        {% trans "Net" %} <img src="static/net-bar.png" class="metadata-bar" /><br /><br />
79
                        {% trans "details" %}
80
                    </div>
81
                    <div class="vm-metadata metadata-column">
82
                        <div class="metadata-left">
83
                            {% trans "Metadata" %}: <br />
84
                            (<span class="metadata-count">0</span>)
85
                        </div>
86
                        <div class="metadata-keys-container">
87
                            <div class="scrollable vertical">
88
                                <div class="items">
89
                                </div>
90
                            </div>
91
                            <div class="metadata-actions">
92
                                <div class="prev"></div>
93
                                <div class="next"></div>
94
                            </div>
95
                        </div>
96
                        <a href="#" class="manage-metadata">{% trans "Manage Tags" %}</a>
97
                    </div>
98
                </div>
99
            </div>
100
            <div class="state">
101
                <div class="status">{% trans "Running" %}</div>
102
                <div class="indicators">
103
                    <div class="indicator1"></div>
104
                    <div class="indicator2"></div>
105
                    <div class="indicator3"></div>
106
                    <div class="indicator4"></div>
107
                </div>
108
                <img class="spinner" style="display:none" src="static/icons/indicators/medium/progress.gif" />
109
                <img class="wave" style="display:none" src="static/icons/indicators/medium/wave.gif" />
110
            </div>
111
            <div class="actions">
112
                <div class="action-container start">
113
                    <a href="#" class="action-start">{% trans "Start" %}</a>
114
                    <div class="confirm_single">
115
                        <button class="yes">{% trans "Confirm" %}</button>
116
                        <button class="no">X</button>
117
                    </div>
118
                </div>
119
                <div class="action-container reboot">
120
                    <a href="#" class="action-reboot">{% trans "Reboot" %}</a>
121
                    <div class="confirm_single">
122
                        <button class="yes">{% trans "Confirm" %}</button>
123
                        <button class="no">X</button>
124
                    </div>
125
                </div>
126
                <div class="action-container shutdown">
127
                    <a href="#" class="action-shutdown">{% trans "Shutdown" %}</a>
128
                    <div class="confirm_single">
129
                        <button class="yes">{% trans "Confirm" %}</button>
130
                        <button class="no">X</button>
131
                    </div>
132
                </div>
133
                <div class="action-container console">
134
                    <a href="#" class="action-console">{% trans "Console" %}</a>
135
                    <div class="confirm_single">
136
                        <button class="yes">{% trans "Confirm" %}</button>
137
                        <button class="no">X</button>
138
                    </div>
139
                </div>
140
                <div class="action-container destroy">
141
                    <a href="#" class="action-destroy">{% trans "Destroy" %}</a>
142
                    <div class="confirm_single">
143
                        <button class="yes">{% trans "Confirm" %}</button>
144
                        <button class="no">X</button>
145
                    </div>
146
                </div>
147
            </div>
148
            <div class="action_error" align="center">
149
                {% trans "<span>Error</span> on" %} <span class="action">{% trans "error action" %}</span>
150
                <span class="code"></span>
151
                <span class="message"></span>
152
                <button class="details">{% trans "Details" %}</button>
153
            </div>
154
        </div>
155
        <div class="separator"></div>
156
    </div>
157
    <div class="running"><div class="large-spinner"></div></div>
158
    <div class="terminated" style="display:none;"></div>
159
</div>
160

    
161
<script>
162
CONFIRMBOX_OFFSET = 200;
163

164
// actions on machine mouseover
165
$("#machinesview-icon.standard .machine").live('mouseover', function() {
166
    // show connect button only if the machine is active
167
    if ($(this).find('.status').text() == STATUSES['ACTIVE']) {
168
        $(this).find("div.connect-arrow").show();
169
        $(this).find("div.connect-border").show();
170
    }
171
});
172

173
// actions on machine mouseout
174
$("#machinesview-icon.standard .machine").live('mouseout', function() {
175
    // hide connect button
176
    $(this).find("div.connect-arrow").hide();
177
    $(this).find("div.connect-border").hide();
178
});
179

180
// actions on connect arrow border mouseover
181
$("#machinesview-icon.standard .running div.connect-border").live('mouseover', function() {
182
    $(this).next().addClass('border-hover');
183
});
184

185
// actions on connect arrow border mouseout
186
$("#machinesview-icon.standard .running div.connect-border").live('mouseout', function() {
187
    $(this).next().removeClass('border-hover');
188
});
189

190
// open console on machine logo click
191
$("#machinesview-icon.standard .running img.logo").live('click', function(){
192
    $(this).parent().parent().find("a.action-console").click();
193
    return false;
194
});
195

196
// open console on connect arrow click
197
$("#machinesview-icon.standard .running div.connect-arrow").live('click', function(){
198
    $(this).parent().parent().find("a.action-console").click();
199
    return false;
200
});
201

202
// open console on connect arrow border click
203
$("#machinesview-icon.standard .running div.connect-border").live('click', function(){
204
    $(this).parent().parent().find("a.action-console").click();
205
    return false;
206
});
207

208
//hide the all of the info contents
209
$("#machinesview-icon.standard .info-content").hide();
210
//toggle the component with class info-content
211
$("#machinesview-icon.standard div.info-header").live('click', function() {
212
    if ($(this).find('.toggler').hasClass('up')) {
213
        $(this).find('.toggler').removeClass('up');
214
        $(this).find('.toggler').addClass('down');
215
        $(this).find('.info-label').removeClass('darker');
216
        $(this).parent().parent().removeClass('light-background');
217
    } else {
218
        $(this).find('.toggler').removeClass('down');
219
        $(this).find('.toggler').addClass('up');
220
        $(this).find('.info-label').addClass('darker');
221
        $(this).parent().parent().addClass('light-background');
222
    }
223
    $(this).parent().parent().find(".info-content").slideToggle(600);
224
    return false;
225
});
226

227
// intercept manage metadata click
228
$("#machinesview-icon.standard a.manage-metadata").live('click', function() {
229
    // get server name and server ID
230
    var serverID = $(this).closest('.machine-container').attr("id");
231
    var serverName = $(this).closest('.machine').find("span.name").text();
232
    // set server name to all related metadata dialogs
233
    $("#metadata-wizard div.machine-name").text(serverName);
234
    if ($(this).closest('.machine-container').parent().hasClass('terminated')) {
235
        $("#metadata-wizard div#on-off").text('off');
236
    } else {
237
        $("#metadata-wizard div#on-off").text('on');
238
    }
239
    // set server id to all related metadata dialogs
240
    $("#metadata-wizard p").text(serverID);
241
    show_metadata_wizard();
242
    return false;
243
});
244

245
//initiate machine renaming
246
$("#machinesview-icon.standard .rename, #machinesview-icon.standard h5.editable span.name").live('click', function() {
247
    $(this).parent().find('.name').html("<input id=\"txtEdit\" type=\"text\" class=\"nametextbox\" value=\"" +
248
                                        $(this).parent().find('.name').text() +
249
                                        "\" / ><span class=\"oldValue\">" +
250
                                        $(this).parent().find('.name').text() + "</span>");
251
    $(this).parent().find('.rename').hide();
252
    $(this).parent().find(".editbuttons").fadeIn();
253
    $(this).parent().find(".nametextbox").focus().select();
254
    $(this).parent().removeClass('editable');
255

256
    //submit wizard by pressing enter on the name textbox
257
    $("#txtEdit").keydown(function (e) {
258
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
259
            $(this).parent().parent().find('div.editbuttons span.save').click();
260
            return false;
261
        } else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
262
            $(this).parent().parent().find('div.editbuttons span.cancel').click();
263
            return true;
264
        }
265
    });
266
    return false;
267
});
268

269
//rename machine
270
$("#machinesview-icon.standard .editbuttons .save").live('click', function() {
271
    serverID = $(this).closest('.machine-container').attr("id");
272
    serverName = $(this).parent().parent().find('.name').find('.nametextbox').val();
273
    if (serverName.trim() == ''){
274
        return false;
275
    }
276
    $(this).parent().parent().find('.name').html($(this).parent().parent().find('.nametextbox').val());
277
    $(this).parent().parent().find(".editbuttons").fadeOut("fast");
278
    $(this).parent().parent().find(".rename").fadeIn("slow");
279
    rename(serverID, serverName);
280
    return false;
281
});
282

283
//cancel renaming
284
$("#machinesview-icon.standard .editbuttons .cancel").live('click', function() {
285
    $(this).parent().parent().find('.name').html($(this).parent().parent().find('.oldValue').text());
286
    $(this).parent().parent().find(".editbuttons").hide();
287
    $(this).parent().parent().find(".rename").fadeIn();
288
    $(this).parent().parent().addClass('editable');
289
    return false;
290
});
291

292
// intercept reboot click
293
$("#machinesview-icon.standard div.actions a.action-reboot").live('click', function() {
294
    // get server id and server name from DOM
295
    var serverID = $(this).closest("div.machine-container").attr("id");
296
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
297
    var found = false;
298
    // show/hide proper menus
299
    $(this).parent().parent().find('a').removeClass('selected');
300
    $(this).addClass('selected');
301
    $(this).parent().parent().addClass('display');
302
    $(this).closest("div.machine").find('.action_error').hide();
303
    // if there is already a pending action for this server replace it
304
    for (i=0; i<pending_actions.length; i++) {
305
        if (pending_actions[i][1] == serverID) {
306
            pending_actions[i][0] = reboot;
307
            found = true
308
        }
309
    }
310
    // no pending action for this server was found, so let's just add it to the list
311
    if (!found)
312
        pending_actions.push([reboot, serverID, serverName])
313
    // pass the proper action to update confirmation boxes
314
    update_confirmations();
315
    return false;
316
});
317

318
// intercept shutdown click
319
$("#machinesview-icon.standard div.actions a.action-shutdown").live('click', function() {
320
    // get server id and server name from DOM
321
    var serverID = $(this).closest("div.machine-container").attr("id");
322
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
323
    var found = false;
324
    // show/hide proper menus
325
    $(this).parent().parent().find('a').removeClass('selected');
326
    $(this).addClass('selected');
327
    $(this).parent().parent().addClass('display');
328
    $(this).closest("div.machine").find('.action_error').hide();
329
    // if there is already a pending action for this server replace it
330
    for (i=0; i<pending_actions.length; i++) {
331
        if (pending_actions[i][1] == serverID) {
332
            pending_actions[i][0] = shutdown;
333
            found = true
334
        }
335
    }
336
    // no pending action for this server was found, so let's just add it to the list
337
    if (!found)
338
        pending_actions.push([shutdown, serverID, serverName])
339
    update_confirmations();
340
    return false;
341
});
342

343
// intercept start click
344
$("#machinesview-icon.standard div.actions a.action-start").live('click', function() {
345
    // get server id and server name from DOM
346
    var serverID = $(this).closest("div.machine-container").attr("id");
347
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
348
    var found = false;
349
    // show/hide proper menus
350
    $(this).parent().parent().find('a').removeClass('selected');
351
    $(this).addClass('selected');
352
    $(this).parent().parent().addClass('display');
353
    $(this).closest("div.machine").find('.action_error').hide();
354
    // if there is already a pending action for this server replace it
355
    for (i=0; i<pending_actions.length; i++) {
356
        if (pending_actions[i][1] == serverID) {
357
            pending_actions[i][0] = start;
358
            found = true
359
        }
360
    }
361
    // no pending action for this server was found, so let's just add it to the list
362
    if (!found)
363
        pending_actions.push([start, serverID, serverName])
364
    update_confirmations();
365
    return false;
366
});
367

368
// intercept console click
369
$("#machinesview-icon.standard div.actions a.action-console").live('click', function() {
370
    // get server id and server name from DOM
371
    var serverID = $(this).closest("div.machine-container").attr("id");
372
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
373
    var found = false;
374
    // show/hide proper menus
375
    $(this).parent().parent().find('a').removeClass('selected');
376
    $(this).addClass('selected');
377
    $(this).parent().parent().addClass('display');
378
    $(this).closest("div.machine").find('.action_error').hide();
379
    // if there is already a pending action for this server replace it
380
    for (i=0; i<pending_actions.length; i++) {
381
        if (pending_actions[i][1] == serverID) {
382
            pending_actions[i][0] = open_console;
383
            found = true
384
        }
385
    }
386
    // no pending action for this server was found, so let's just add it to the list
387
    if (!found)
388
        pending_actions.push([open_console, serverID, serverName])
389
    update_confirmations();
390
    return false;
391
});
392

393

394
// intercept destroy click
395
$("#machinesview-icon.standard div.actions a.action-destroy").live('click', function() {
396
    // get server id and server name from DOM
397
    var serverID = $(this).closest("div.machine-container").attr("id");
398
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
399
    var found = false;
400
    // show/hide proper menus
401
    $(this).parent().parent().find('a').removeClass('selected');
402
    $(this).addClass('selected');
403
    $(this).parent().parent().addClass('display');
404
    $(this).closest("div.machine").find('.action_error').hide();
405
    // if there is already a pending action for this server replace it
406
    for (i=0; i<pending_actions.length; i++) {
407
        if (pending_actions[i][1] == serverID) {
408
            pending_actions[i][0] = destroy;
409
            found = true
410
        }
411
    }
412
    // no pending action for this server was found, so let's just add it to the list
413
    if (!found)
414
        pending_actions.push([destroy, serverID, serverName])
415
    update_confirmations();
416
    return false;
417
});
418

419
$("#machinesview-icon.standard div.confirm_single button.yes").live('click', function(){
420
    var serverID = $(this).closest("div.machine-container").attr("id");
421
    // if there is a pending action for this server execute it
422
    for (i=0; i<pending_actions.length; i++) {
423
        if (pending_actions[i][1]==serverID){
424
            action = pending_actions.splice(i,1)[0]; // extract action
425
            // change the status text in cases where no api state exists
426
            if (action[0] == start) {
427
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Starting']);
428
                $(this).closest("div.machine").find('.state').removeClass().addClass('state starting-state');
429
                $(this).closest("div.machine").find('.spinner').show();
430
            } else if (action[0] == shutdown) {
431
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Shutting down']);
432
                $(this).closest("div.machine").find('.state').removeClass().addClass('state shutting-state');
433
                $(this).closest("div.machine").find('.spinner').show();
434
            } else if (action[0] == reboot) {
435
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Rebooting']);
436
                $(this).closest("div.machine").find('.state').removeClass().addClass('state rebooting-state');
437
                $(this).closest("div.machine").find('.spinner').show();
438
            }  else if (action[0] == destroy) {
439
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Destroying']);
440
                $(this).closest("div.machine").find('.state').removeClass().addClass('state destroying-state');
441
                $(this).closest("div.machine").find('.spinner').show();
442
            }
443
            action[0]([action[1]]); // execute action
444
        }
445
    }
446
    $(this).parent().hide();
447
    $(this).closest('div.actions').find('a').removeClass('selected');
448
    $(this).closest("div.machine").children('.state').children('.spinner').show()
449
    $(this).closest("div.machine").children('div.actions').removeClass('display');
450
    update_confirmations();
451
    return false;
452
});
453

454
$("#machinesview-icon.standard div.confirm_single button.no").live('click', function(){
455
    // remove the action from the pending list
456
    var serverID = $(this).closest("div.machine-container").attr("id");
457

458
    $(this).closest('div.action-container').children('a').removeClass('selected');
459
    $(this).closest('div.actions').removeClass('display');
460
    for (i=0; i<pending_actions.length; i++) { // if there is a pending action for this server remove it
461
        if (pending_actions[i][1] == serverID) {
462
            pending_actions.splice(i,1);
463
        }
464
    }
465
    $(this).parent().hide();
466
    update_confirmations();
467
    return false;
468
});
469

470
$("#machinesview-icon.standard div.action_error .details").live('click', function(){
471
    // remove the action from the pending list
472
    ajax_error($(this).parent().children('.code').text(), undefined, $(this).parent().children('.action').text(), $(this).parent().children('.message').text());
473
    $(this).parent().hide();
474
});
475

476
// update the servers list
477
function update_machines_view(data) {
478
    /*
479
    Go through the servers in the input data. Update existing entries, add
480
    new ones to the list
481
    */
482
    $.each(data.servers.values, function(i,server) {
483
        // get DOM element, if it exists
484
        existing = $('#machinesview-icon.standard #' + server.id);
485
        // get server OS, if it exists
486
        if (!(server.metadata == undefined)) {
487
            var server_image = os_icon(server.metadata);
488
        } else {
489
            var server_image = "unknown"
490
        }
491
        // get server status message, if it exists
492
        var current_message = existing.find(".status").text();
493
        // if multiple machines exist in the DOM, delete all but one
494
        // defensive coding - that shouldn't happen normally
495
        while (existing.length > 1){
496
            existing.remove();
497
        }
498
        // if server already exists in DOM, update its values
499
        if (existing.length){
500
            //  if the status is deleted
501
            if (server.status == 'DELETED') {
502
                // delete server entry from the DOM
503
                log_server_status_change(existing, 'DELETED');
504
                existing.remove();
505
            }
506
            // if the status has changed
507
            else if ( current_message != STATUSES[server.status]) {
508
                /*
509
                Here there are 4 possibilities:
510
                    1. From an active state to an inactive one
511
                    2. From an inactive state to an active one
512
                    3. From an active state to a different active one
513
                    4. From an inactive state to a different inactive one
514
                The last two (3, 4) can be dealt with the same way
515
                */
516
                if (ACTIVE_STATES.indexOf(current_message) >= 0 &&
517
                    INACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0) {
518
                    // from an active state to an inactive one
519
                    log_server_status_change(existing, server.status);
520
                    moved = existing.clone().appendTo("#machinesview-icon.standard .terminated");
521
                    moved.find("img.logo").attr("src",'static/icons/machines/medium/' + server_image + '-off.png');
522
                    existing.remove();
523
                    existing = moved;
524
                    existing.find(".status").text(STATUSES[server.status]);
525
                    existing.find('.spinner').hide();
526
                    if ($("div.terminated").find("div.machine-container").length > 0) {
527
                        $("div.terminated").show();
528
                    }
529
                    existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
530
                    existing.find('.state').removeClass().addClass('state terminated-state');
531
                    setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
532
                }
533
                else if (INACTIVE_STATES.indexOf(current_message) >= 0 &&
534
                         ACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0) {
535
                    // From an inactive state to an active one
536
                    log_server_status_change(existing, server.status);
537
                    moved = existing.clone().appendTo("#machinesview-icon.standard .running");
538
                    moved.find("img.logo").attr('src','static/icons/machines/medium/' + server_image + '-on.png');
539
                    existing.remove();
540
                    existing = moved;
541
                    existing.find(".status").text(STATUSES[server.status]);
542
                    existing.find('.spinner').hide();
543
                    if ($("div.terminated").find("div.machine-container").length == 0) {
544
                        $("div.terminated").hide();
545
                    }
546
                    existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
547
                    existing.find('.state').removeClass().addClass('state running-state');
548
                    setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
549
                }
550
                else {
551
                    // handling active to active or inactive to inactive changes
552
                    if (TRANSITIONS[current_message] && TRANSITIONS[current_message] != 'Rebooting') {
553
                        // don't do anything if it is still in transition
554
                    }
555
                    else if ((TRANSITIONS[current_message] == 'Rebooting' && server.status == 'ACTIVE') ||
556
                             (STATUSES['BUILD'] == current_message && server.status == 'ACTIVE')) {
557
                        // if it has been rebooted or just created
558
                        log_server_status_change(existing, server.status);
559
                        existing.find(".status").text(STATUSES[server.status]);
560
                        existing.find('.spinner').hide();
561
                        existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
562
                        existing.find('.state').removeClass().addClass('state running-state');
563
                        setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
564
                    }
565
                    else {
566
                        // in any other case just change the status and ignore spinners/waves
567
                        existing.find(".status").text(STATUSES[server.status]);
568
                        existing.appendTo("#machinesview-icon.standard .running");
569
                        existing.find('.state').removeClass().addClass('state running-state');
570
                    }
571
                }
572
            }
573
            // find and display ips
574
            var ips = get_public_ips(server);
575
            existing.find("a.ip span.public").text(ips['ip4']);
576
        }
577
        // if it doesn't exist and the server is not DELETED, make a new entry
578
        else if ( server.status != 'DELETED') {
579
            // clone the proper template and put basic values in
580
            var machine = $("#machinesview-icon.standard #machine-container-template").clone().attr("id", server.id).fadeIn("slow");
581
            machine.find(".scrollable").scrollable({vertical: true});
582
            machine.find("div.name span.name").text(server.name.substring(0,100));
583
            machine.find("span.imagetag").text(server_image);
584
            machine.find(".status").text(STATUSES[server.status]);
585
            // check server status to select where to append the new server to
586
            if (ACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0 ) {
587
                // append to running
588
                machine.find("img.logo").attr("src","static/icons/machines/medium/"+server_image+'-on.png');
589
                machine.appendTo("#machinesview-icon.standard .running");
590
            } else {
591
                // append to terminated
592
                machine.find("img.logo").attr("src","static/icons/machines/medium/"+server_image+'-off.png');
593
                machine.appendTo("#machinesview-icon.standard .terminated");
594
                if (server.status == "STOPPED") { //if server status us stopped is a different case than status unknown/error
595
                    machine.find('.state').removeClass().addClass('state terminated-state');
596
                } else {
597
                       machine.find('.state').removeClass().addClass('state error-state');
598
                }
599
            }
600
            //show spinner if server is still building or rebooting
601
            if (server.status == 'BUILD') {
602
                machine.find('.spinner').show();
603
                machine.find('.state').removeClass().addClass('state build-state');
604
            }
605
            if (server.status == 'REBOOT') {
606
                machine.find('.spinner').show();
607
                machine.find('.state').removeClass().addClass('state rebooting-state');
608
            }
609
            // find and display flavor parameters
610
            var flavor_params = get_flavor_params(server.flavorRef);
611
            machine.find(".cpu-data").text(flavor_params['cpus']);
612
            machine.find(".ram-data").text(flavor_params['ram']);
613
            machine.find(".disk-data").text(flavor_params['disk']);
614
            // find and display image parameters
615
            var image_params = get_image_params(server.imageRef);
616
            machine.find(".image-data").text(image_params['name'].substring(0,15));
617
            machine.find(".image-size-data").text(image_params['size']);
618
            // find and display ips
619
            var ips = get_public_ips(server);
620
            machine.find("a.ip span.public").text(ips['ip4']);
621
        }
622
        /*
623
        Do some repeated actions that include:
624
            1. Update actions
625
            2. Metadata list updating
626
        */
627
        update_iconview_actions(server.id, server.status);
628
        if (!(server.metadata == undefined)) {
629
                list_metadata_keys(server.id, server.metadata.values);
630
        }
631
    });
632
    /*
633
    Do some standard stuff, repeated each time
634
    FIXME: Can these be moved to a new function?
635
    */
636
    $("div.running > div.large-spinner").hide();
637
    // show all separators and hide the last one
638
    $("#machinesview-icon.standard div.machine-container div.separator").show();
639
    $("#machinesview-icon.standard div.machine-container:last-child").find("div.separator").hide();
640
    // the terminated div shows only when terminated machines are available
641
    if ($("#machinesview-icon.standard .terminated div.name").length > 0) {
642
        $("div.terminated").fadeIn("slow");
643
    } else {
644
        $("div.terminated").fadeOut("slow");
645
    }
646
    // show message in case user has no servers!
647
    if ($('#machinesview-icon .machine-container').length < 2) {
648
        showWelcome();
649
    } else {
650
        hideWelcome();
651
    }
652
    // set confirm box position
653
    if (window.innerHeight - CONFIRMBOX_OFFSET < $('#machinesview-icon.standard').height()) {
654
        $('.confirm_multiple').addClass('fixed');
655
    } else {
656
        $('.confirm_multiple').removeClass('fixed');
657
    }
658
}
659

660
// reposition multiple confirmation box on window resize
661
$(window).resize(function(){
662
    if (this.innerHeight - CONFIRMBOX_OFFSET < $('#machinesview-icon').height())
663
        $('.confirm_multiple').addClass('fixed');
664
    else
665
        $('.confirm_multiple').removeClass('fixed');
666
});
667

668
// update metadata list
669
function list_metadata_keys(serverID, keys) {
670
    // empty the list if it already exists
671
    $("#machinesview-icon.standard div.#" +serverID).find("div.items").empty();
672
    //start counter
673
    var i=0;
674
    // show values
675
    for (var key in keys) {
676
        $("#machinesview-icon.standard div.#" +serverID).find(".items").append("<div class='item'>" + key + "</div>");
677
        i++;
678
    }
679
    //hide the metadata controls if we have less than 3 metadata
680
    if (i <= 3) {
681
        $("#machinesview-icon.standard div.#" +serverID).find(".metadata-actions").hide();
682
    }
683
    //show the metadata controls if we have more than 3 metadata
684
    if (i > 3) {
685
        $("#machinesview-icon.standard div.#" +serverID).find(".metadata-actions").show();
686
    }
687
    $("#machinesview-icon.standard div.#" +serverID).find(".metadata-count").text(i);
688
}
689

690
// indicate that the requested action was succesfully completed
691
function display_success(serverID) {
692

693
}
694

695
// indicate that the requested action was not completed
696
function display_failure(status, serverID, action, responseText) {
697
    $('#machinesview-icon.standard #'+serverID+ ' .spinner').hide();
698
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .action').text(action);
699
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .code').text(status);
700
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .message').text(responseText);
701
    $('#machinesview-icon.standard #'+serverID+ ' .action_error').show();
702
}
703

704
// basic functions executed on page load
705
if ( flavors.length == 0 && images.length == 0 ) {
706
    // configure flavors, this also calls update_vms(UPDATE_INTERVAL)
707
    update_flavors();
708
    // populate image list
709
    update_images();
710
} else if ( flavors.length == 0 && images.length != 0 ) {
711
    // configure flavors, this also calls update_vms(UPDATE_INTERVAL)
712
    update_flavors();
713
} else if ( flavors.length != 0 && images.length == 0 ) {
714
    // populate image list
715
    update_images();
716
    update_vms(UPDATE_INTERVAL);
717
} else {
718
    // start updating vm list
719
    update_vms(UPDATE_INTERVAL);
720
}
721

722
// set the label of the multiple buttons
723
$('.confirm_multiple button.yes').text('Confirm All');
724
$('.confirm_multiple button.no').text('Cancel All');
725

726

727
if ($.browser.msie) {
728
    //IE fix for div hover
729
    $("div.machine").live("mouseenter", function () {
730
        $(this).css("background-color","#A1C8DB");
731
        $(this).find(".actions a").css("color","black");
732
    });
733
    $("div.machine").live("mouseleave", function () {
734
        $(this).css("background-color","transparent");
735
        $(this).find(".actions a").css("color","transparent");
736
    });
737
}
738
</script>