Statistics
| Branch: | Tag: | Revision:

root / ui / templates / standard.html @ 33282d93

History | View | Annotate | Download (16.5 kB)

1
{% load i18n %}
2

    
3
<!-- the standard view -->
4
<div id="machinesview" class="standard">
5
    <div id="spinner"></div>
6
    <div class="machine" id="machine-template" style="display:none">
7
        <div class="actions">
8
            <a href="#" class="action-start">{% trans "Start" %}</a>
9
            <a href="#" class="action-reboot">{% trans "Reboot" %}</a>
10
            <a href="#" class="action-shutdown">{% trans "Shutdown" %}</a>
11
            <a href="#" class="action-destroy">{% trans "Destroy" %}</a>
12
        </div>        
13
        <div class="state">
14
            <div class="status">{% trans "Running" %}</div>
15
            <div class="indicator"></div>
16
            <div class="indicator"></div>
17
            <div class="indicator"></div>
18
            <div class="indicator"></div>
19
            <img class="spinner" style="display:none" src="/static/progress.gif" />
20
            <img class="wave" style="display:none" src="/static/wave.gif" />
21
        </div>
22
        <img class="logo" src="" />
23
        <a href="#" class="name">
24
            <h5>{% trans "Name: " %}<span class="name">node.name</span><span class="rename"></span></h5>
25
        </a>
26
        <a href="#" class="ip">
27
            <h5>{% trans "IP: " %}<span class="public">node.public_ip</span></h5>
28
        </a>
29
        <h5 class="settings">
30
            {% trans "Show:" %} <a href="#">{% trans "disks" %}</a> | <a href="#">{% trans "networks" %}</a> | <a href="#">{% trans "group" %}</a>
31
        </h5>
32

    
33
        <div class="confirm_single">
34
            <button class="yes">{% trans "Confirm" %}</button>
35
            <button class="no">{% trans "Cancel" %}</button>
36
        </div>
37
        <div class="action_error" align="center">
38
            {% trans "<span class='orange'>Error</span> on" %} <span class="action">{% trans "error action" %}</span>
39
            <span class="code"></span>            
40
            <span class="message"></span>
41
            <button class="details">{% trans "Details" %}</button>
42
        </div>
43
        <div class="separator"></div>
44
    </div>
45

    
46
    <div class="running"></div>
47
    <div id="mini" class="separator"></div>
48
    <div class="terminated"></div>
49
</div>
50

    
51
<script>
52
    
53
// intercept reboot click 
54
$("div.actions a.action-reboot").live('click', function(){
55
    var serverID = $(this).parent().parent().attr("id");
56
    var serverName = $(this).parent().prevAll("a.name").find("span.name").text();
57
    var found = false;
58
    
59
    $(this).parent().children('a').removeClass('selected');
60
    $(this).addClass('selected');
61
    $(this).parent().addClass('display');
62
    $(this).parent().parent().find('.action_error').hide();
63
    for (i=0;i<pending_actions.length;i++){ // if there is already a pending action for this server replace it
64
        if (pending_actions[i][1]==serverID){
65
            pending_actions[i][0] = reboot;
66
            found = true
67
        }
68
    }
69
    if (!found) // no pending action for this server was found, so let's just add it to the list
70
        pending_actions.push([reboot, serverID, serverName])
71
    update_confirmations();
72
    return false;
73
});
74

75
// intercept shutdown click
76
$("div.actions a.action-shutdown").live('click', function(){ 
77
    var serverID = $(this).parent().parent().attr("id");
78
    var serverName = $(this).parent().prevAll("a.name").find("span.name").text();
79
    var found = false;
80
    $(this).parent().children('a').removeClass('selected');
81
    $(this).addClass('selected');
82
    $(this).parent().addClass('display')
83
    $(this).parent().parent().find('.action_error').hide();
84

85
    for (i=0;i<pending_actions.length;i++){ // if there is already a pending action for this server replace it
86
        if (pending_actions[i][1]==serverID){
87
            pending_actions[i][0] = shutdown;
88
            found = true
89
        }
90
    }
91
    if (!found) // no pending action for this server was found, so let's just add it to the list 
92
        pending_actions.push([shutdown, serverID, serverName])
93
    update_confirmations();
94
    return false;
95
});
96

97
// intercept start click
98
$("div.actions a.action-start").live('click', function(){ 
99
    var serverID = $(this).parent().parent().attr("id");
100
    var serverName = $(this).parent().prevAll("a.name").find("span.name").text();
101
    var found = false;
102
    $(this).parent().children('a').removeClass('selected');
103
    $(this).addClass('selected');
104
    $(this).parent().addClass('display')
105
    $(this).parent().parent().find('.action_error').hide();
106

107
    for (i=0;i<pending_actions.length;i++){ // if there is already a pending action for this server replace it
108
        if (pending_actions[i][1]==serverID){
109
            pending_actions[i][0] = start;
110
            found = true
111
        }
112
    }
113
    if (!found) // no pending action for this server was found, so let's just add it to the list
114
        pending_actions.push([start, serverID, serverName])
115
    update_confirmations();    
116
    return false;
117
});
118

119
// intercept destroy click
120
$("div.actions a.action-destroy").live('click', function(){ 
121
    var serverID = $(this).parent().parent().attr("id");
122
    var serverName = $(this).parent().prevAll("a.name").find("span.name").text();
123
    var found = false;
124
    $(this).parent().children('a').removeClass('selected');
125
    $(this).addClass('selected');
126
    $(this).parent().addClass('display')
127
    $(this).parent().parent().find('.action_error').hide();
128

129
    for (i=0;i<pending_actions.length;i++){ // if there is already a pending action for this server replace it
130
        if (pending_actions[i][1]==serverID){
131
            pending_actions[i][0] = destroy;
132
            found = true
133
        }
134
    }
135
    if (!found) // no pending action for this server was found, so let's just add it to the list
136
        pending_actions.push([destroy, serverID, serverName])
137
    update_confirmations();    
138
    return false;
139
});
140

141
$("div.confirm_single .yes").live('click', function(){
142
    var serverID = $(this).parent().parent().attr("id");
143
    for (i=0;i<pending_actions.length;i++){ // if there is a pending action for this server execute it
144
        if (pending_actions[i][1]==serverID){
145
            action = pending_actions.splice(i,1)[0]; // extract action
146
            // change the status text in cases where no api state exists
147
            if (action[0] == start) {
148
                $(this).parent().parent().find('.status').text('Starting');
149
                $(this).parent().parent().find('.spinner').show();
150
            } else if (action[0] == shutdown) {
151
                $(this).parent().parent().find('.status').text('Shutting down');
152
                $(this).parent().parent().find('.spinner').show();
153
            } else if (action[0] == reboot) {
154
                $(this).parent().parent().find('.status').text('Rebooting');
155
                $(this).parent().parent().find('.spinner').show();
156
            }  else if (action[0] == destroy) {
157
                $(this).parent().parent().find('.status').text('Destroying');
158
                $(this).parent().parent().find('.spinner').show();
159
            }                    
160
            action[0]([action[1]]); // execute action
161
        }
162
    }
163
    $(this).parent().hide();
164
    $(this).parent().parent().children('div.actions').children('a').removeClass('selected');
165
    $(this).parent().parent().children('.state').children('.spinner').show()
166
    $(this).parent().parent().children('div.actions').removeClass('display');
167
    update_confirmations(); 
168
    return false;
169
});
170

171
$("div.confirm_single .no").live('click', function(){
172
    // remove the action from the pending list
173
    var serverID = $(this).parent().parent().attr("id");
174
    
175
    $(this).parent().parent().children('div.actions').children('a').removeClass('selected');
176
    $(this).parent().parent().children('div.actions').removeClass('display');    
177
    for (i=0;i<pending_actions.length;i++){ // if there is a pending action for this server remove it
178
        if (pending_actions[i][1]==serverID){
179
            pending_actions.splice(i,1);
180
        }
181
    }
182
    $(this).parent().hide();
183
    update_confirmations();    
184
    return false;
185
});
186

187
$("div.action_error .details").live('click', function(){
188
    // remove the action from the pending list
189
    ajax_error($(this).parent().children('.code').text(), undefined, $(this).parent().children('.action').text(), $(this).parent().children('.message').text());
190
    $(this).parent().hide();
191
});
192

193

194
// update the servers list
195
function update_machines_view(data){
196
    /* 
197
    Go through the servers in the input data. Update existing entries, add
198
    new ones to the list
199
    */     
200
           
201
    $.each(data.servers.values, function(i,server){
202
        existing = $('#' + server.id);
203
        
204
        // if multiple machines exist in the DOM, delete all but one
205
        // defensive coding - that shouldn't happen normally
206
        while (existing.length > 1){
207
            existing.remove();
208
        }
209

210
        var server_image = os_icon(server.metadata);
211

212

213
        // server already exists in DOM
214
        if (existing.length){
215
            $("div.machine:last-child").find("div.separator").show();                
216

217
            //  if the status is deleted, delete it from the DOM
218
            if (server.status == 'DELETED') {
219
                existing.remove();            
220
                try {
221
                    console.info(existing.find("a.name span.name").text() + ' removed');
222
                } catch(err) {}            
223
            } else if (existing.find(".status").text() != STATUS_MESSAGES[server.status]) {
224

225
                try { // firebug console logging
226
                    console.info(existing.find("a.name span.name").text() + ' from ' 
227
                                + existing.find(".status").text() + ' to ' + STATUS_MESSAGES[server.status]);
228
                } catch(err) {}
229
                //show reboot and shutdown actions
230
                if (server.status == 'ACTIVE' || server.status == 'REBOOT') {
231
                    $('div.#' + server.id + ' a.action-reboot').show();
232
                    $('div.#' + server.id + ' a.action-shutdown').show();        
233
                    $('div.#' + server.id + ' a.action-destroy').removeClass('destroy-padding');        
234
                }
235
                if (['BUILD','ACTIVE','REBOOT'].indexOf(server.status) >= 0 &&
236
                    [STATUS_MESSAGES['STOPPED'], STATUS_MESSAGES['ERROR'],
237
                     'Starting'].indexOf(existing.find(".status").text()) >= 0) {
238
                    // from stopped, on error or starting to building, active or rebooting
239
                    // starting is not an api state, it means the vm is stopped or on error
240
                    moved = existing.clone().appendTo(".running");
241
                    moved.find("img.logo").attr("src","static/machines/" + server_image + '-on.png');
242
                    existing.remove();
243
                    existing = moved;
244
                    existing.find(".status").text(STATUS_MESSAGES[server.status]); 
245
                } else if (['STOPPED','ERROR'].indexOf(server.status) >= 0 &&
246
                           [STATUS_MESSAGES['ACTIVE'], STATUS_MESSAGES['BUILD'], STATUS_MESSAGES['REBOOT'],
247
                            'Shutting down'].indexOf(existing.find(".status").text()) >= 0) {
248
                    // from active, building, rebooting, or shutting down to stopped or on error
249
                    // shutting down is not an api state, it means the server is active
250
                    moved = existing.clone().appendTo(".terminated");
251
                    moved.find("img.logo").attr("src","static/machines/" + server_image + '-off.png');
252
                    existing.remove();
253
                    existing = moved;
254
                    existing.find(".status").text(STATUS_MESSAGES[server.status]); 
255
                } else if (['BUILD','ACTIVE','REBOOT'].indexOf(server.status) >= 0 && 
256
                            [STATUS_MESSAGES['ACTIVE'], STATUS_MESSAGES['BUILD'],
257
                             STATUS_MESSAGES['REBOOT']].indexOf(existing.find(".status").text()) >= 0) {
258
                    // the server changes status, but remains in running list
259
                    existing.find(".status").text(STATUS_MESSAGES[server.status]); 
260
                } else if (['STOPPED','ERROR'].indexOf(server.status) >= 0 &&
261
                    [STATUS_MESSAGES['STOPPED'], 
262
                     STATUS_MESSAGES['ERROR']].indexOf(existing.find(".status").text()) >= 0) {
263
                    // the server changes status, but remains in terminated list
264
                    existing.find(".status").text(STATUS_MESSAGES[server.status]); 
265
                }        
266
                existing.find('.spinner').hide();
267
                existing.find(' .wave').attr('src','static/wave.gif').show();
268
                setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
269
                // show spinner while the server is rebooting, starting or shutting down  
270
                if ([STATUS_MESSAGES['REBOOT'], 
271
                    'Starting', 'Shutting down'].indexOf(existing.find(".status").text()) >= 0 ) {
272
                    existing.find(' .wave').hide();
273
                    existing.find('.spinner').show();
274
                }                            
275
            }
276
            existing.find("a.name span.name").text(server.name);
277
            existing.find("a.ip span.public").text(String(server.addresses.values[0].values[0].addr).replace(',',' '));
278
        } else if (server.status != 'DELETED') {
279
            // If it does not exist and it's not deleted, we should create it
280
            var machine = $("#machine-template").clone().attr("id", server.id).fadeIn("slow");
281
            machine.find("a.name span.name").text(server.name);
282
            machine.find("img.logo").attr("src","static/machines/"+server_image+'-on.png');
283
            machine.find("span.imagetag").text(server_image);
284
            machine.find("a.ip span.public").text(String(server.addresses.values[0].values[0].addr).replace(',',' '));            
285
            machine.find(".status").text(STATUS_MESSAGES[server.status]);
286
            if (['BUILD', 'ACTIVE', 'REBOOT'].indexOf(server.status) >= 0){
287
                machine.appendTo(".running");
288
            } else {
289
                machine.find("img.logo").attr("src","static/machines/"+server_image+'-off.png');
290
                machine.appendTo(".terminated");
291
            }
292
            //show spinner while machine is building
293
            if (server.status == 'BUILD' || 
294
                ['Starting', 'Shutting down'].indexOf(existing.find(".status").text()) >= 0 ) { 
295
                machine.find('.spinner').show();
296
            }   
297
            //allow destroy action only while machine is building
298
            if (server.status == 'BUILD') {
299
                $('div.#' + server.id + ' a.action-reboot').hide();
300
                $('div.#' + server.id + ' a.action-shutdown').hide();        
301
                $('div.#' + server.id + ' a.action-destroy').addClass('destroy-padding');        
302
            }
303
        }
304
    });
305

306
    $("#spinner").hide();
307
    // show all separators
308
    $("div.machine div.separator").show();
309
    // hide the last one
310
    $("div.machine:last-child").find("div.separator").hide();
311
    // the separator shows only when running and terminated machines are available
312
    if ($(".terminated a.name").length > 0 && $(".running a.name").length > 0) {
313
        $("#mini.separator").fadeIn("slow");
314
    } else {
315
        $("#mini.separator").fadeOut("slow");
316
    }     
317

318
    // show message in case user has no servers!
319
    if (servers.length == 0) {
320
        showWelcome()
321
    } else {
322
        hideWelcome()
323
    }  
324
    
325
    // set confirm box position
326
    if (window.innerHeight - 220 < $('#machinesview').height())
327
        $('.confirm_multiple').addClass('fixed');
328
    else
329
        $('.confirm_multiple').removeClass('fixed');
330
}
331

332
// indicate that the requested action was succesfully completed
333
function display_success(serverID) {
334

335
}
336

337
// indicate that the requested action was not completed
338
function display_failure(status, serverID, action, responseText) {
339
    $('#'+serverID+ ' .spinner').hide();
340
    $('#'+serverID+ ' .action_error .action').text(action);
341
    $('#'+serverID+ ' .action_error .code').text(status);
342
    $('#'+serverID+ ' .action_error .message').text(responseText);
343
    $('#'+serverID+ ' .action_error').show();
344
    
345
}
346

347
if (images.length == 0) {
348
    // populate image list
349
    update_images();
350
}
351
if (flavors.length == 0) {
352
    // configure flavors
353
    update_flavors(); 
354
}
355
// set the label of the multiple buttons 
356
$('div.confirm_multiple button.yes').text('Confirm All');
357
$('div.confirm_multiple button.no').text('Cancel All');
358

359
// reposition multiple confirmation box on window resize
360
$(window).resize(function(){
361
    if (this.innerHeight - 220 < $('#machinesview').height())
362
        $('.confirm_multiple').addClass('fixed');
363
    else
364
        $('.confirm_multiple').removeClass('fixed');
365
});
366

367
// start updating vm list
368
update_vms(UPDATE_INTERVAL);
369
</script>