]> git.argeo.org Git - gpl/argeo-slc.git/blob - server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/BatchView.js
Added LIST_RESULTS_LONG service
[gpl/argeo-slc.git] / server / org.argeo.slc.ria / src / argeo-ria-lib / slc / class / org / argeo / slc / ria / BatchView.js
1 /**
2 * Applet for the batch manager
3 */
4 qx.Class.define("org.argeo.slc.ria.BatchView",
5 {
6 extend : qx.ui.container.Composite,
7 implement : [org.argeo.ria.components.IView],
8 include : [org.argeo.ria.session.MPrefHolder],
9 statics : {
10 riaPreferences : {
11 "slc.batch.delete.confirm" : {
12 label : "Confirm on batch deletion",
13 type : "boolean",
14 defaultValue : true
15 },
16 "slc.batch.autoclear" : {
17 label : "Autoclear batch on execution",
18 type : "boolean",
19 defaultValue : false
20 }
21 }
22 },
23 properties :
24 {
25 /**
26 * The commands definition Map that will be automatically added and wired to the menubar and toolbar.
27 * See {@link org.argeo.ria.event.CommandsManager#definitions} for the keys to use for defining commands.
28 */
29 commands : {
30 init : {
31 "submitform" : {
32 label : "Execute Batch",
33 icon : "org.argeo.slc.ria/media-playback-start.png",
34 shortcut : null,
35 enabled : false,
36 menu : "Launcher",
37 toolbar : "batch",
38 callback : function(e) {
39 var batchAgentId = this.getBatchAgentId();
40 if (!batchAgentId) {
41 return;
42 }
43 var prefName = "slc.batch.autoclear";
44 var prefValue = this.getRiaPreferenceValue(prefName);
45 if(prefValue !== null && prefValue === true){
46 this.executeBatchOnAgent(batchAgentId, true);
47 }else{
48 this.executeBatchOnAgent(batchAgentId, false);
49 }
50 return;
51 var modal = new org.argeo.ria.components.Modal("Clear?", null);
52 modal.addYesNoReminder("Do you want to clear the batch automatically after execution?", prefName);
53 modal.addListener("cancel", function(e){
54 this.executeBatchOnAgent(batchAgentId, false);
55 }, this);
56 modal.addListener("ok", function(e){
57 this.executeBatchOnAgent(batchAgentId, true);
58 }, this);
59 modal.attachAndShow();
60 },
61 command : null
62 },
63 /*
64 "toggleopenonadd" : {
65 label : "Auto edit on Add",
66 icon : "org.argeo.slc.ria/document-open.png",
67 shortcut : null,
68 enabled : true,
69 toggle : true,
70 toggleInitialState : true,
71 menu : "Launcher",
72 toolbar : "launcher",
73 callback : function(event) {
74 var state = event.getTarget().getUserData("slc.command.toggleState");
75 this.setAutoOpen(state);
76 },
77 command : null
78 },
79 "editexecutionspecs" : {
80 label : "Edit Execution Specs",
81 icon : "org.argeo.slc.ria/document-open.png",
82 shortcut : null,
83 enabled : false,
84 menu : "Launcher",
85 toolbar : "batch",
86 callback : function(e) {
87 var sel = this.list.getSortedSelection();
88 var spec = sel[0].getUserData("batchEntrySpec");
89 if (spec.hasEditableValues()) {
90 var specEditor = new org.argeo.slc.ria.execution.SpecEditor(spec);
91 specEditor.attachAndShow();
92 }
93 },
94 selectionChange : function(viewId, selection) {
95 if (viewId != "batch:list")
96 return;
97 this.setEnabled(false);
98 if ((selection && selection.length == 1)) {
99 var selectedItemSpec = selection[0].getUserData("batchEntrySpec");
100 if (selectedItemSpec.hasEditableValues()) {
101 this.setEnabled(true);
102 }
103 }
104 },
105 command : null
106 },
107 */
108 "removefrombatch" : {
109 label : "Remove from batch",
110 icon : "org.argeo.slc.ria/edit-delete.png",
111 shortcut : null,
112 enabled : false,
113 menu : "Launcher",
114 toolbar : "batch",
115 callback : function(e) {
116 var sel = this.list.getSortedSelection();
117 var confirmPref = this.getRiaPreferenceValue("slc.batch.delete.confirm");
118 var execution = function() {
119 for (var i = 0; i < sel.length; i++) {
120 this.list.remove(sel[i]);
121 }
122 if (!this.list.hasChildren()) {
123 this.setBatchAgentId(null);
124 }
125 }
126 if(confirmPref){
127 var modal = new org.argeo.ria.components.Modal("Confirm", null);
128 modal.addConfirm("Are you sure you want to remove<br> the selected test"
129 + (sel.length > 1 ? "s" : "")
130 + " from the Batch?");
131 modal.addListener("ok", execution, this);
132 modal.attachAndShow();
133 }else{
134 execution = qx.lang.Function.bind(execution, this);
135 execution();
136 }
137 },
138 selectionChange : function(viewId, selection) {
139 if (viewId != "batch:list")
140 return;
141 this.setEnabled(false);
142 if ((selection && selection.length > 0))
143 this.setEnabled(true);
144 },
145 command : null
146 },
147 "clearbatch" : {
148 label : "Clear batch",
149 icon : "org.argeo.slc.ria/user-trash-full.png",
150 shortcut : null,
151 enabled : true,
152 menu : "Launcher",
153 toolbar : "batch",
154 callback : function(e) {
155 if(!this.list.hasChildren()) return;
156 this.list.selectAll();
157 this.getCommands()["removefrombatch"].command.execute();
158 },
159 selectionChange : function(viewId, selection) {
160 },
161 command : null
162 }
163 }
164 },
165 view : {
166 init : null
167 },
168 viewSelection : {
169 nullable:false,
170 check:"org.argeo.ria.components.ViewSelection"
171 },
172 instanceId : {init:""},
173 instanceLabel : {init:""},
174 /**
175 * A boolean registering whether the SpecEditor must autoOpen or not
176 * when a spec is added to the Batch.
177 */
178 autoOpen : {
179 init : true,
180 check : "Boolean"
181 },
182 batchAgentId : {
183 init : null,
184 nullable : true,
185 check : "String",
186 event : "changeBatchAgentId"
187 }
188 },
189
190 construct : function(){
191 this.base(arguments);
192 this.setLayout(new qx.ui.layout.Dock());
193 },
194
195 members : {
196 /**
197 * The implementation should contain the GUI initialisation.
198 * This is the role of the manager to actually add the graphical component to the pane,
199 * so it's not necessary to do it here.
200 * @param viewPane {org.argeo.ria.components.ViewPane} The pane manager
201 * @param data {Mixed} Any object or data passed by the initiator of the view
202 * @return {Boolean}
203 */
204 init : function(viewPane, data){
205 this.setView(viewPane);
206 this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));
207 this._emptyAgentString = "Empty Batch (Drop scripts here)";
208 this._crtAgentString = "Batch Execution on Agent ";
209
210 },
211 /**
212 * The implementation should contain the real data loading (i.o. query...)
213 * @return {Boolean}
214 */
215 load : function(){
216 this._createLayout();
217 this.getView().setViewTitle(this._emptyAgentString);
218 //this.getView().setViewTitle("");
219 },
220
221 /**
222 * Creates the main applet layout.
223 */
224 _createLayout : function() {
225 this.listPane = new qx.ui.container.Composite(new qx.ui.layout.Dock());
226 this.addListener("changeBatchAgentId", function(event) {
227 var value = event.getData();
228 if (value == null) {
229 this.getView().setViewTitle(this._emptyAgentString);
230 } else {
231 var selectorView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("selector").getContent();
232 if(selectorView){
233 var agentsMap = selectorView.getAgentsMap();
234 this.getView().setViewTitle(this._crtAgentString + "'" + agentsMap[value] + "'");
235 }
236 }
237 }, this);
238
239 var indicator = new qx.ui.core.Widget();
240 indicator.setDecorator(new qx.ui.decoration.Single().set({
241 top : [1, "solid", "#33508D"]
242 }));
243 indicator.setHeight(0);
244 indicator.setOpacity(0.5);
245 indicator.setZIndex(100);
246 indicator.setLayoutProperties({
247 left : -1000,
248 top : -1000
249 });
250 org.argeo.ria.Application.INSTANCE.getRoot().add(indicator);
251
252 this.list = new qx.ui.form.List();
253 this.list.setDecorator(null);
254 this.list.setSelectionMode("multi");
255 this.list.setDroppable(true);
256 this.list.setDraggable(true);
257 this.list.setContextMenu(org.argeo.ria.event.CommandsManager
258 .getInstance().createMenuFromIds(["removefrombatch"]));
259
260 this.list.addListener("dragstart", function(e) {
261 e.addType(["items"]);
262 e.addAction(["move"]);
263 }, this);
264 this.list.addListener("dragend", function(e) {
265 indicator.setDomPosition(-1000, -1000);
266 });
267 this.list.addListener("dragover", function(e) {
268 var orig = e.getOriginalTarget();
269 var origCoords = orig.getContainerLocation();
270 indicator.setWidth(orig.getBounds().width);
271 indicator.setDomPosition(origCoords.left,
272 origCoords.bottom);
273 });
274 this.list.addListener("drag", function(e) {
275 var orig = e.getOriginalTarget();
276 var origCoords = orig.getContainerLocation();
277 indicator.setWidth(orig.getBounds().width);
278 indicator.setDomPosition(origCoords.left,
279 origCoords.bottom);
280 });
281
282 this.list.addListener("drop", function(e) {
283 var target = e.getRelatedTarget();
284 var afterItem = e.getOriginalTarget();
285 indicator.setDomPosition(-1000, -1000);
286 if (afterItem.classname != "qx.ui.form.ListItem")
287 afterItem = null;
288 if (!target) {
289 target = this.list.getSortedSelection()[0];
290 this.addFlowToBatch(target, afterItem);
291 } else {
292 org.argeo.ria.event.CommandsManager.getInstance().executeCommand("addtobatch");
293 }
294 }, this);
295 this.listPane.add(this.list, {
296 edge : "center"
297 });
298
299 this.list.addListener("changeSelection", function(e) {
300 var viewSelection = this.getViewSelection();
301 viewSelection.setViewId("batch:list");
302 viewSelection.clear();
303 var listSel = this.list.getSortedSelection();
304 for (var i = 0; i < listSel.length; i++) {
305 viewSelection.addNode(listSel[i]);
306 }
307 }, this);
308
309 this.dropDecorator = new qx.ui.decoration.Background();
310 this.dropDecorator.set({
311 backgroundImage : "org.argeo.slc.ria/drophere.gif",
312 backgroundRepeat : "no-repeat"
313 });
314
315
316 listChangeListener = function() {
317 var command = org.argeo.ria.event.CommandsManager.getInstance()
318 .getCommandById("submitform");
319 command.setEnabled(this.list.hasChildren());
320 var command2 = org.argeo.ria.event.CommandsManager.getInstance()
321 .getCommandById("clearbatch");
322 command2.setEnabled(this.list.hasChildren());
323 this.list.setDecorator((this.list.hasChildren()?null:this.dropDecorator));
324 };
325 this.list.addListener("addItem", listChangeListener, this);
326 this.list.addListener("removeItem", listChangeListener, this);
327
328 this.list.setDecorator(this.dropDecorator);
329
330 this.add(this.listPane);
331 },
332
333
334 /**
335 * Adds a given ExecutionFlow to the batch
336 *
337 * @param target
338 * {mixed} The dropped target, can be a TreeFile (add) or a
339 * ListItem (reorder).
340 * @param after
341 * {qx.ui.form.ListItem} Optional list item : if set, the
342 * flow will be added as a new list item positionned after
343 * this one.
344 * @param skipAutoOpen
345 * {boolean} Whether the formular should open or not.
346 */
347 addFlowToBatch : function(target, after, skipAutoOpen) {
348 if (target && target.classname == "qx.ui.form.ListItem") {
349 if (!after)
350 return;
351 if (after == "first")
352 this.list.addAt(target, 0);
353 else
354 this.list.addAfter(target, after);
355 return;
356 }
357
358 // Folder case
359 if (qx.Class.isSubClassOf(qx.Class.getByName(target.classname),
360 qx.ui.tree.TreeFolder)) {
361 var allChildren = target.getItems(true);
362 for (var i = 0; i < allChildren.length; i++) {
363 if (allChildren[i].getUserData("executionFlow")) {
364 try{
365 this.addFlowToBatch(allChildren[i], null, true);
366 }catch(e){
367 return;
368 }
369 }
370 }
371 return;
372 }
373
374 // Check agent Uuid against current batch agent Id.
375 var agentUuid = target.getUserData("agentUuid");
376 if (!this.getBatchAgentId()) {
377 this.setBatchAgentId(agentUuid);
378 } else if (this.getBatchAgentId() != agentUuid) {
379 this.error("Batch can contain tests only of the same agent!");
380 throw new Error("Batch can contain tests only of the same agent!");
381 }
382
383 var executionModule = target.getUserData("executionModule");
384 var executionFlow = target.getUserData("executionFlow");
385 var batchEntry = new org.argeo.slc.ria.execution.BatchEntrySpec(
386 executionModule, executionFlow);
387
388 this.appendBatchEntrySpec(batchEntry, target.getIcon(), after);
389 },
390
391 appendBatchEntrySpec: function(batchEntrySpec, icon, after){
392
393 var item = new qx.ui.form.ListItem(batchEntrySpec.getLabel(), icon || "org.argeo.slc.ria/system.png");
394 item.setUserData("batchEntrySpec", batchEntrySpec);
395 item.setPaddingTop(1);
396 item.setPaddingBottom(2);
397 if (after) {
398 if (after == "first")
399 this.list.addAt(item, 0);
400 else
401 this.list.addAfter(item, after);
402 } else {
403 this.list.add(item);
404 }
405 this.list.setSelection([item]);
406
407 },
408
409 /**
410 * Called at execution
411 *
412 * @param agentUuid
413 * {String} The id of the target agent
414 */
415 executeBatchOnAgent : function(agentUuid, clearBatch) {
416 var selection = this.list.getChildren();
417 if (!selection.length)
418 return;
419 // Get Host
420 var agentsMap = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("selector").getContent().getAgentsMap();
421 var host = agentsMap[agentUuid];
422 var slcExecMessage = new org.argeo.slc.ria.execution.Message();
423 slcExecMessage.setHost(host);
424 for (var i = 0; i < selection.length; i++) {
425 var batchEntrySpec = selection[i].getUserData("batchEntrySpec");
426 slcExecMessage.addBatchEntrySpec(batchEntrySpec);
427 }
428 try{
429 var xmlMessage = slcExecMessage.toXml();
430 if(!window.xmlExecStub){
431 window.xmlExecStub = {};
432 }
433 window.xmlExecStub[slcExecMessage.getUuid()] = qx.xml.Document.fromString(xmlMessage);
434 var req = org.argeo.slc.ria.SlcApi.getNewSlcExecutionService(
435 agentUuid, xmlMessage);
436 req.send();
437 // Force logs refresh right now!
438 qx.event.Timer.once(function() {
439 var command = org.argeo.ria.event.CommandsManager
440 .getInstance().getCommandById("reloadlogs");
441 if (command) {
442 command.execute();
443 }
444 }, this, 2000);
445 if(clearBatch){
446 req.addListener("completed", function(e){
447 this.list.removeAll();
448 this.setBatchAgentId(null);
449 }, this);
450 }
451 }catch(e){
452 this.error(e);
453 }
454 },
455
456 clearBatchForAgentId : function(agentId){
457 if(this.getBatchAgentId() == agentId){
458 this.list.removeAll();
459 this.setBatchAgentId(null);
460 }
461 },
462
463 /**
464 * Whether this component is already contained in a scroller (return false) or not (return true).
465 * @return {Boolean}
466 */
467 addScroll : function(){return false;},
468 /**
469 * Called at destruction time
470 * Perform all the clean operations (stopping polling queries, etc.)
471 */
472 close : function(){return true;}
473 }
474
475
476 });