1
|
define([
|
2
|
"dojo/on",
|
3
|
'dojo/_base/lang',
|
4
|
'steam2/statusColorMap',
|
5
|
'steam2/user',
|
6
|
'stabile/griddialog',
|
7
|
'dojox/grid/DataGrid',
|
8
|
'dojo/string',
|
9
|
'stabile/stores'
|
10
|
], function(on, lang, statusColorMap, user){
|
11
|
|
12
|
var grid = {
|
13
|
|
14
|
// Gets a text representation of an action button with action handlers.
|
15
|
actionButton: function(args){
|
16
|
var actionHandler;
|
17
|
args.title = args.title || args.action;
|
18
|
if(args.confirm){
|
19
|
if (args.actionHandler)
|
20
|
actionHandler = "grid.actionConfirmDialog('" + args.id + "','" + args.action + "','" + args.name + "','" + args.title + "','" + args.type + "','" + args.actionHandler + "')";
|
21
|
else
|
22
|
actionHandler = "grid.actionConfirmDialog('" + args.id + "','" + args.action + "','" + args.name + "','" + args.title + "','" + args.type + "')";
|
23
|
}
|
24
|
else{
|
25
|
if (args.actionHandler)
|
26
|
actionHandler = args.actionHandler + "('" + args.id + "','" + args.action + "','" + args.type + "')";
|
27
|
else
|
28
|
actionHandler = "grid.actionHandler('" + args.id + "','" + args.action + "','" + args.type + "')";
|
29
|
}
|
30
|
// left out button text intentionally since image replacement didn't work out in IE
|
31
|
var t = '<button type="button" title="${title}" class="action_button ${action}_icon" id="${action}_${id}" onclick="${actionHandler};return false;"><span>${action}</span></button>';
|
32
|
args.actionHandler = actionHandler;
|
33
|
return dojo.string.substitute(t, args);
|
34
|
},
|
35
|
|
36
|
actionCheckBox: function(args){
|
37
|
return '<input id="bulk-action-' + args.id + '" "class="bulk-action" type="checkbox" />';
|
38
|
},
|
39
|
|
40
|
// Gets a text representation of a save button.
|
41
|
// args:
|
42
|
// type {String}: grid to save, e.g., images, servers
|
43
|
saveButton : function(type){
|
44
|
// returning false, to disable form submit
|
45
|
var actionHandler = "grid.saveHandler('" + type + "'); return false;";
|
46
|
var t = '<button type="submit" title="Save" class="btn btn-sm btn-primary pull-right" onclick="${actionHandler}">Save</button>';
|
47
|
return dojo.string.substitute(t, {'actionHandler':actionHandler});
|
48
|
},
|
49
|
|
50
|
// save the contents of the dialog.
|
51
|
// FIXME: bad naming
|
52
|
// args:
|
53
|
// name {String}: name of grid object
|
54
|
saveHandler : function(name){
|
55
|
// FIXME: action "" == "save"
|
56
|
// We have to set the action since there might be a leftover from an
|
57
|
// old action
|
58
|
if (window[name].grid.dialog.item.action) { // action is not initialized for new items //co
|
59
|
window[name].store.setValue(window[name].grid.dialog.item, 'action', "");
|
60
|
}
|
61
|
window[name].grid.dialog.save();
|
62
|
},
|
63
|
|
64
|
// Shows actions confirm dialog.
|
65
|
// args:
|
66
|
// id {String}: id of item
|
67
|
// action {String}: the action to perform
|
68
|
// name {String}: the name of the object, e.g., servers, images
|
69
|
actionConfirmDialog: function(id, action, name, title, type, myactionHandler){
|
70
|
if(!id || !action || !name || !title || !type){
|
71
|
console.error("not all arguments supplied!", arguments);
|
72
|
}
|
73
|
var actionHandler = "grid.actionHandler";
|
74
|
if (myactionHandler) actionHandler = myactionHandler;
|
75
|
var content = [
|
76
|
'<div align="center" style="margin: 18px;"><p>Are you sure you want to ${title}</p>',
|
77
|
'<div>',
|
78
|
'<button class="btn btn-danger btn-sm" onClick="' + actionHandler + '(\'${id}\',\'${action}\',\'${type}\');dijit.byId(\'confirmDialog\').hide()">OK</button> ',
|
79
|
'<button class="btn btn-info btn-sm" onClick="dijit.byId(\'confirmDialog\').hide()">Cancel</button></button>',
|
80
|
'</div></div>'].join('');
|
81
|
content = dojo.string.substitute(content, {'id':id, 'action':action, 'type': type, 'title':title});
|
82
|
var dialog = dijit.byId('confirmDialog');
|
83
|
if(!dialog){
|
84
|
dialog = new dijit.Dialog({ id: 'confirmDialog', style: "width: 300px"});
|
85
|
}
|
86
|
dialog.set('title', type + ": " + name);
|
87
|
dialog.set('content', content);
|
88
|
dialog.show();
|
89
|
return dialog;
|
90
|
},
|
91
|
|
92
|
alertDialog: function(title, content, myactionHandler, parm1, parm2){
|
93
|
var content = [
|
94
|
'<div align="center" style="padding:10px;">',
|
95
|
content,
|
96
|
'<div>',
|
97
|
'<button class="btn btn-primary" onClick="' + myactionHandler + '(\'${parm1}\',\'${parm2}\'); dijit.byId(\'alertDialog\').hide()">OK</button>',
|
98
|
'</div></div>'].join('');
|
99
|
content = dojo.string.substitute(content, {'parm1':parm1, 'parm2':parm2});
|
100
|
var dialog = dijit.byId('alertDialog');
|
101
|
if(!dialog){
|
102
|
dialog = new dijit.Dialog({ id: 'alertDialog', style: "width: 300px"});
|
103
|
}
|
104
|
dialog.set('title', title);
|
105
|
dialog.set('content', content );
|
106
|
dialog.show();
|
107
|
return dialog;
|
108
|
},
|
109
|
|
110
|
// Performs the given action on the given object.
|
111
|
actionHandler: function(id, action, type){
|
112
|
var store = stores[type];
|
113
|
var item = store.fetchItemByIdentity({
|
114
|
identity: id,
|
115
|
onItem: function(item, request){
|
116
|
// HACK: special case when dowloading images.
|
117
|
// FIXME: move these specialcases away.
|
118
|
if(action == "download"){
|
119
|
// somehow, path isn't of the String type: appending "" to it to ensure that.
|
120
|
//window.location.href = (item.path + "").replace('/mnt/stabile/images/', '/stabile/download/');
|
121
|
//window.location.href = "/stabile/images?action=download&image=" + escape(item.path + "");
|
122
|
window.location.href = "/stabile/images?action=download&uuid=" + item.uuid;
|
123
|
return;
|
124
|
}
|
125
|
|
126
|
var data = {
|
127
|
"items": [{uuid:store.getValue(item, "uuid"), action:action}]
|
128
|
};
|
129
|
|
130
|
if (type == "nodes") {
|
131
|
data = {"items": [{mac:item.mac, action:action}]};
|
132
|
} else if (type == "users") {
|
133
|
data = {"items": [{username:item.username, action:action}]};
|
134
|
}
|
135
|
|
136
|
else if(action == "start"){
|
137
|
var value = dijit.byId('mac') && dijit.byId('mac').get('value');
|
138
|
if (user.is_admin && value && value!="" & value !="--") {
|
139
|
data = {
|
140
|
"items": [{uuid:store.getValue(item, "uuid"), action:action, mac:value}]
|
141
|
};
|
142
|
}
|
143
|
}
|
144
|
|
145
|
if ((action == 'delete' || action=='deleteentirely') && (type == 'servers' || type == 'images'|| type == 'networks'|| type == 'nodes'|| type == 'users')) {
|
146
|
if(window[type].grid.dialog.isOpen()){window[type].grid.dialog.hide();}
|
147
|
store.deleteItem(item);
|
148
|
store.save({onComplete: function(){
|
149
|
if (type == 'servers')
|
150
|
home.grid.updatePending = images.grid.updatePending = networks.grid.updatePending = true;
|
151
|
}});
|
152
|
} else {
|
153
|
// send action to server
|
154
|
dojo.xhrPost({
|
155
|
url: "/stabile/" + type,
|
156
|
postData: dojo.toJson(data),
|
157
|
load: function(response){
|
158
|
|
159
|
if (type == 'servers')
|
160
|
home.grid.updatePending = images.grid.updatePending = networks.grid.updatePending = true;
|
161
|
|
162
|
var newstatus = server.parseResponse(response)["status"];
|
163
|
console.log("response", newstatus, item);
|
164
|
if (item.status != newstatus)
|
165
|
ui_update.publish([{"type": "update","tab": type, "status": newstatus, "uuid": item.uuid}])
|
166
|
|
167
|
if((action === "delete" /*|| action === "master" */) && window[type].grid.dialog.isOpen())
|
168
|
{window[type].grid.dialog.hide();}
|
169
|
|
170
|
// Also update systems on home tab when deleting servers
|
171
|
if (action == 'delete' && type == 'servers'){
|
172
|
steam2.stores.systems.fetchItemByIdentity({
|
173
|
identity: id,
|
174
|
onItem: function(item, request){
|
175
|
if (action == 'delete') {
|
176
|
home.grid.removeSystem(item);
|
177
|
}
|
178
|
}
|
179
|
});
|
180
|
}
|
181
|
|
182
|
},
|
183
|
error: function(error){
|
184
|
console.error("grid::actionHandler", error);
|
185
|
}
|
186
|
});
|
187
|
}
|
188
|
dojo.publish(type + ":" + action, item);
|
189
|
}
|
190
|
});
|
191
|
},
|
192
|
|
193
|
// Creates the grid.
|
194
|
create: function(args){
|
195
|
// exceptions are apparantly caught by dojo in onLoad
|
196
|
if(!args){console.error("args must be supplied");}
|
197
|
if(!args.store) {console.error("store property must be supplied in args");}
|
198
|
if(!args.structure) {console.error("structure property must be supplied args");} //
|
199
|
if(!args.dialogStructure) {console.error("dialogStructure property must be supplied args");}
|
200
|
|
201
|
dojo.forEach(args.structure, function(s){
|
202
|
if (s.hidden && user.is_admin) s.hidden = false;
|
203
|
});
|
204
|
|
205
|
var self = new dojox.grid.DataGrid({
|
206
|
singleClickEdit:false,//true,
|
207
|
clientSort: true,
|
208
|
sortInfo: args.sortInfo || 1,
|
209
|
store: args.store,
|
210
|
structure: args.structure,
|
211
|
rowSelector: "4px",
|
212
|
query: args.storeQuery || { },
|
213
|
queryOptions: { ignoreCase:true, cache:true },
|
214
|
autoRender: true,
|
215
|
autoHeight: false,
|
216
|
rowsPerPage: 2000,
|
217
|
selectionMode: "single",
|
218
|
class: args['class'] || "grid-div",
|
219
|
|
220
|
renderTooltip: function(){
|
221
|
//var q = dojo.query('.irigo-tooltip', this.domNode);
|
222
|
var q = dojo.query('.irigo-tooltip');
|
223
|
if(q.irigoTooltip){q.irigoTooltip();}
|
224
|
},
|
225
|
postrender: function(){
|
226
|
this.renderTooltip();
|
227
|
if(this.onPostRender) {this.onPostRender();}
|
228
|
}
|
229
|
// autoHeight: true // is broken
|
230
|
}, args.domnode);
|
231
|
|
232
|
self.model = args.model;
|
233
|
self.name = args.name;
|
234
|
self.dialogStructure = args.dialogStructure;
|
235
|
self.dialogExtras = args.dialogExtras;
|
236
|
self.rowStyler = args.rowStyler;
|
237
|
self.updatePending = true;
|
238
|
|
239
|
if(args.canSort){self.canSort = args.canSort;}
|
240
|
|
241
|
//Fixme: onDialog no longer used...?
|
242
|
//self.onDialog = args.onDialog;
|
243
|
self.onDialogButtons = args.onDialogButtons;
|
244
|
self.onBeforeDialog = args.onBeforeDialog;
|
245
|
self.onPostRender = args.onPostRender;
|
246
|
self.currentEditHandler = null;
|
247
|
self.onBeforeSave = args.onBeforeSave;
|
248
|
self.getActionButtons = args.getActionButtons;
|
249
|
|
250
|
self.dialog = griddialog(self);
|
251
|
|
252
|
self.onStyleRow = function(row){
|
253
|
/*var item = self.getItem(row.index);
|
254
|
if(item){
|
255
|
var status = self.store.getValue(item,"status");
|
256
|
var color = statusColorMap.get(status);
|
257
|
row.customStyles = "cursor:pointer; color:" + color;
|
258
|
dojo.setStyle(self.getRowNode(row.index), "color", statusColorMap.get(status)); // ugly
|
259
|
if(self.rowStyler){self.rowStyler(row, item);}
|
260
|
};*/
|
261
|
};
|
262
|
|
263
|
on(self, "styleRow", function(row){
|
264
|
row.customStyles = "cursor:pointer;";
|
265
|
var item = self.getItem(row.index);
|
266
|
if(item){
|
267
|
//var status = self.store.getValue(item,"status");
|
268
|
//var color = statusColorMap.get(status);
|
269
|
var color = statusColorMap.get(item.status);
|
270
|
//row.customStyles += "color:" + color + ";";
|
271
|
row.customClasses += " " + color;
|
272
|
self.focus.styleRow(row);
|
273
|
//self.edit.styleRow(row);
|
274
|
//dojo.setStyle(self.getRowNode(row.index), "color", color); // ugly
|
275
|
if(self.rowStyler){self.rowStyler(row, item);}
|
276
|
};
|
277
|
});
|
278
|
|
279
|
self.onFetchError = function(err,req) {
|
280
|
//location = "/stabile/auth/login";
|
281
|
};
|
282
|
|
283
|
self.refresh = function(){
|
284
|
var storename;
|
285
|
if (self.store == stores['servers']) storename = "servers";
|
286
|
else if (self.store == stores['images']) storename = "images";
|
287
|
else if (self.store == stores['networks']) storename = "images";
|
288
|
else if (self.store == stores['systems']) storename = "systems";
|
289
|
else if (self.store == stores['users']) storename = "users";
|
290
|
else if (self.store == stores['nodes']) storename = "nodes";
|
291
|
console.log("refreshing", storename, self);
|
292
|
self.store.reset();
|
293
|
};
|
294
|
|
295
|
self.refreshRow = function(task, idprop) {
|
296
|
if (!idprop) idprop = "uuid";
|
297
|
self.store.fetchItemByIdentity({identity: task[idprop],
|
298
|
onItem: function(item){
|
299
|
for (var key in task) {
|
300
|
if (key=='id' || key=='sender' || key=='timestamp' || key=='type' || key=='uuid') {;}
|
301
|
else if (item[key]) {
|
302
|
item[key] = task[key];
|
303
|
}
|
304
|
}
|
305
|
self.store.save();
|
306
|
var i = self.getItemIndex(item);
|
307
|
if (task.tab == 'images' && images.grid.getRowNode(i)) images.grid.getRowNode(i).style["font-weight"]='';
|
308
|
self.updateRow(i);
|
309
|
self.updateRowStyles(i);
|
310
|
if (window[task.tab].updateSums) window[task.tab].updateSums();
|
311
|
//dojo.setStyle(self.getRowNode(i), "color", statusColorMap.get(item.status)); // ugly
|
312
|
}
|
313
|
});
|
314
|
};
|
315
|
|
316
|
self.handleSelectTab = function(e){
|
317
|
if(!e || e.id == self.name){
|
318
|
if (self.updatePending) {
|
319
|
self.updatePending = false;
|
320
|
console.log("doing pending refresh", self.name);
|
321
|
// self.refresh();
|
322
|
}
|
323
|
self.refresh();
|
324
|
var that = this;
|
325
|
setTimeout(function() {
|
326
|
that.renderTooltip();
|
327
|
}, 1000)
|
328
|
}
|
329
|
}
|
330
|
|
331
|
|
332
|
// save the grid and refresh it
|
333
|
self.save = function(args){
|
334
|
if(self.store.isDirty()){
|
335
|
self.store.save({
|
336
|
onComplete: function(){
|
337
|
if (!self.store.isDirty()) {
|
338
|
// if (!self.name == "images" && !self.name == "networks") {self.refresh();}
|
339
|
}
|
340
|
if(args.onComplete){
|
341
|
args.onComplete();
|
342
|
}
|
343
|
},
|
344
|
onError: function(){
|
345
|
console.log("Error saving grid");
|
346
|
// self.refresh();
|
347
|
}
|
348
|
});
|
349
|
}
|
350
|
else{
|
351
|
IRIGO.toaster([{
|
352
|
message: "Nothing to commit!",
|
353
|
type: "message",
|
354
|
duration: 3000
|
355
|
}]);
|
356
|
}
|
357
|
};
|
358
|
|
359
|
self.newItem = function(){
|
360
|
var model = self.model();
|
361
|
self.dialog.show(model);
|
362
|
};
|
363
|
|
364
|
self.itemClickHandler = function(event){
|
365
|
var item = self.selection.getSelected()[0];
|
366
|
if(!item){ // e.g. click on header
|
367
|
return;
|
368
|
}
|
369
|
if(event && event.cell && event.cell.field == 'action' || event.cell.steamid == 'console'|| event.cell.steamid == 'terminal'){
|
370
|
return;
|
371
|
}
|
372
|
if(item.id && (item.id=='0' || item.id=='1') && !user.is_admin){ // regular users can not edit built-in networks
|
373
|
return;
|
374
|
}
|
375
|
self.dialog.show(item);
|
376
|
};
|
377
|
|
378
|
self.update = function(task){
|
379
|
var tabid;
|
380
|
if (dijit.byId('tabContainer')) tabid = dijit.byId('tabContainer').selectedChildWidget.id;
|
381
|
if(self.dialog.isOpen()){
|
382
|
return;
|
383
|
}
|
384
|
if(task.tab == self.name || task.force){
|
385
|
self.refresh();
|
386
|
}
|
387
|
};
|
388
|
|
389
|
//dojo.connect(ui_update, 'onUpdate', self, self.update);
|
390
|
dojo.connect(self, 'onRowClick', self.itemClickHandler);
|
391
|
return self;
|
392
|
}// end of create
|
393
|
};
|
394
|
|
395
|
window.grid = grid;
|
396
|
return grid;
|
397
|
});
|
398
|
|
399
|
|
400
|
|
401
|
|
402
|
|