]> git.argeo.org Git - gpl/argeo-slc.git/blob - server/org.argeo.slc.ria/src/main/webapp/argeo-ria-lib/slc/class/org/argeo/slc/ria/NewLauncherApplet.js
Create Argeo SLC RIA project
[gpl/argeo-slc.git] / server / org.argeo.slc.ria / src / main / webapp / argeo-ria-lib / slc / class / org / argeo / slc / ria / NewLauncherApplet.js
1 /**
2 * A simple Hello World applet for documentation purpose.
3 * The only associated command is the "Close" command.
4 */
5 qx.Class.define("org.argeo.slc.ria.NewLauncherApplet",
6 {
7 extend : qx.ui.container.Composite,
8 implement : [org.argeo.ria.components.IView],
9
10 construct : function(){
11 this.base(arguments);
12 this.setLayout(new qx.ui.layout.Dock());
13 },
14
15 properties :
16 {
17 /**
18 * The viewPane inside which this applet is added.
19 */
20 view : {
21 init : null
22 },
23 viewSelection : {
24 nullable:false,
25 check:"org.argeo.ria.components.ViewSelection"
26 },
27 instanceId : {init:""},
28 instanceLabel : {init:""},
29 /**
30 * A boolean registering whether the SpecEditor must autoOpen or not when a spec is added to the Batch.
31 */
32 autoOpen : {
33 init : true,
34 check : "Boolean"
35 },
36 /**
37 * Commands definition, see {@link org.argeo.ria.event.CommandsManager#definitions}
38 */
39 commands : {
40 init : {
41 "submitform" : {
42 label : "Execute Batch On...",
43 icon : "resource/slc/media-playback-start.png",
44 shortcut : null,
45 enabled : true,
46 menu : "Launcher",
47 toolbar : null,
48 callback : function(e){},
49 submenu : [],
50 submenuCallback : function(commandId){
51 //alert("Execute Batch on Agent "+commandId);
52 this.executeBatchOnAgent(commandId);
53 },
54 command : null
55 },
56 "addtobatch" : {
57 label : "Add to batch",
58 icon : "resource/slc/list-add.png",
59 shortcut : null,
60 enabled : true,
61 menu : null,
62 toolbar : null,
63 callback : function(e){
64 this._addFlowToBatch();
65 },
66 selectionChange : function(viewId, selection){
67 if(viewId != "form:tree") return;
68 if(!selection || selection.length != 1) return;
69 var item = selection[0];
70 this.setEnabled(false);
71 if(qx.Class.isSubClassOf(qx.Class.getByName(item.classname), qx.ui.tree.TreeFile)){
72 this.setEnabled(true);
73 }
74
75 },
76 command : null
77 },
78 "toggleopenonadd" : {
79 label : "Auto Open",
80 icon : "resource/slc/document-open.png",
81 shortcut : null,
82 enabled : true,
83 toggle : true,
84 toggleInitialState : true,
85 menu : "Launcher",
86 toolbar : "launcher",
87 callback : function(event){
88 var state = event.getTarget().getUserData("slc.command.toggleState");
89 this.setAutoOpen(state);
90 },
91 command : null
92 },
93 "editexecutionspecs" : {
94 label : "Edit Execution Specs",
95 icon : "resource/slc/document-open.png",
96 shortcut : null,
97 enabled : false,
98 menu : "Launcher",
99 toolbar : null,
100 callback : function(e){
101 var sel = this.list.getSortedSelection();
102 var item = sel[0];
103 var specEditor = new org.argeo.slc.ria.execution.SpecEditor(item.getUserData("batchEntrySpec"));
104 specEditor.attachAndShow();
105 },
106 selectionChange : function(viewId, selection){
107 if(viewId != "form:list") return;
108 this.setEnabled(false);
109 if((selection && selection.length == 1)) this.setEnabled(true);
110 },
111 command : null
112 },
113 "removefrombatch" : {
114 label : "Remove from batch",
115 icon : "resource/slc/edit-delete.png",
116 shortcut : null,
117 enabled : false,
118 menu : "Launcher",
119 toolbar : null,
120 callback : function(e){
121 var sel = this.list.getSortedSelection();
122 var modal = new org.argeo.ria.components.Modal("Confirm", null);
123 modal.addConfirm("Are you sure you want to remove<br> the selected test" + (sel.length>1?"s":"") + " from the Batch?");
124 modal.addListener("ok", function(){
125 for(var i=0;i<sel.length;i++){
126 this.list.remove(sel[i]);
127 }
128 }, this);
129 modal.attachAndShow();
130 },
131 selectionChange : function(viewId, selection){
132 if(viewId != "form:list") return;
133 this.setEnabled(false);
134 if((selection && selection.length > 0)) this.setEnabled(true);
135 },
136 command : null
137 },
138 "reloadagents" : {
139 label : "Reload Agents",
140 icon : "resource/slc/view-refresh.png",
141 shortcut : "Control+r",
142 enabled : true,
143 menu : "Launcher",
144 toolbar : "launcher",
145 callback : function(e){
146 var req = org.argeo.slc.ria.SlcApi.getListAgentsService("agents");
147 req.send();
148 },
149 command : null
150 },
151 "reloadtree" : {
152 label : "Reload",
153 icon : "resource/slc/view-refresh.png",
154 shortcut : "Control+m",
155 enabled : false,
156 menu : "Launcher",
157 toolbar : "launcher",
158 callback : function(e){
159 var selected = this.tree.getSelectedItem();
160 if(selected.classname == "org.argeo.ria.components.DynamicTreeFolder"){
161 if(selected.getUserData("moduleData")){
162 // It's a "module" node, first trigger the reloadBundle.service
163 selected.setUserData("dataModel", {});
164 selected.setEnabled(false);
165 selected.setOpen(false);
166 var moduleData = selected.getUserData("moduleData");
167 var bundleService = org.argeo.slc.ria.SlcApi.getReloadBundleService(moduleData.name, moduleData.version);
168 bundleService.addListener("completed", function(response){
169 selected.setEnabled(true);
170 selected.setOpen(true);
171 selected.reload();
172 }, this);
173 //bundleService.send();
174 //Do not send, not implemented yet, false timer instead.
175 qx.event.Timer.once(function(response){
176 selected.setEnabled(true);
177 selected.setOpen(true);
178 selected.reload();
179 }, this, 2000);
180 }else{
181 selected.reload();
182 }
183 }
184 },
185 selectionChange : function(viewId, selection){
186 if(viewId != "form:tree") return;
187 if(!selection || selection.length != 1) return;
188 var item = selection[0];
189 if(!qx.Class.isSubClassOf(qx.Class.getByName(item.classname), qx.ui.tree.AbstractTreeItem)) return;
190 this.setEnabled(false);
191 if(qx.Class.isSubClassOf(qx.Class.getByName(item.classname), org.argeo.ria.components.DynamicTreeFolder)){
192 this.setEnabled(true);
193 }
194 },
195 command : null
196 }
197 }
198 },
199 /**
200 * A map containing all currently registered agents.
201 */
202 registeredTopics : {
203 init : {},
204 check : "Map",
205 event : "changeRegisteredTopics"
206 }
207 },
208
209 statics : {
210 /**
211 * Loader for the "flow" level : takes a folder containing "moduleData" and create its children.
212 * @param folder {qx.ui.tree.TreeFolder} A Tree folder containing in the key "moduleData" of its user data a map containing the keys {name,version}
213 */
214 flowLoader : function(folder){
215 var moduleData = folder.getUserData("moduleData");
216 //var pathStub = ["", "/test/toto/zobi", "loop"];
217 //var indexStub = 0;
218
219 var req = org.argeo.slc.ria.SlcApi.getLoadExecutionDescriptorService(moduleData.name, moduleData.version);
220 req.addListener("completed", function(response){
221 var executionModule = new org.argeo.slc.ria.execution.Module();
222 executionModule.setXmlNode(response.getContent());
223 var execFlows = executionModule.getExecutionFlows();
224 for(var key in execFlows){
225 var file = new qx.ui.tree.TreeFile(key);
226 var path = execFlows[key].getPath();
227 //path = pathStub[indexStub];
228 //indexStub ++;
229 file.setUserData("executionModule", executionModule);
230 file.setUserData("executionFlow", execFlows[key]);
231 org.argeo.slc.ria.NewLauncherApplet.attachNodeByPath(folder, path, file);
232 folder.appendDragData(file);
233 }
234 folder.setLoaded(true);
235 });
236 req.send();
237 },
238
239 /**
240 * Loader for the "modules" level : takes any tree folder, currently the root folder.
241 * @param folder {qx.ui.tree.TreeFolder} The root folder
242 */
243 modulesLoader : function(folder){
244 var req = org.argeo.slc.ria.SlcApi.getListModulesService();
245 req.addListener("completed", function(response){
246 var descriptors = org.argeo.ria.util.Element.selectNodes(response.getContent(), "slc:object-list/slc:execution-module-descriptor");
247 var mods = {};
248 for(var i=0;i<descriptors.length; i++){
249 var name = org.argeo.ria.util.Element.getSingleNodeText(descriptors[i], "slc:name");
250 var version = org.argeo.ria.util.Element.getSingleNodeText(descriptors[i], "slc:version");
251 if(!mods[name]) mods[name] = [];
252 mods[name].push(version);
253 }
254 var flowLoader = org.argeo.slc.ria.NewLauncherApplet.flowLoader;
255 for(var key in mods){
256 for(var i=0;i<mods[key].length;i++){
257 var versionFolder = new org.argeo.ria.components.DynamicTreeFolder(
258 key + ' ('+mods[key][i]+')',
259 flowLoader,
260 "Loading Flows",
261 folder.getDragData()
262 );
263 folder.add(versionFolder);
264 versionFolder.setUserData("moduleData", {name:key, version:mods[key][i]});
265 }
266 folder.setLoaded(true);
267 }
268 });
269 req.send();
270 },
271
272 /**
273 * Parse a string path and search if there is a root node.
274 * @param rootNode {qx.ui.tree.AbstractTreeItem} The parent node (containing data model)
275 * @param path {String} The path of the node to attach.
276 */
277 attachNodeByPath : function(rootNode, path, childNode){
278 if(!path || path=="" || path == "/" ){
279 rootNode.add(childNode);
280 return;
281 }
282 var model = rootNode.getUserData("dataModel");
283 if(!model){
284 model = {};
285 rootNode.setUserData("dataModel", model);
286 }
287 var parts = path.split("/");
288 var keys = qx.lang.Object.getKeys(model);
289 var crtPath = "/";
290 var crtFolder = rootNode;
291 for(var i=0;i<parts.length;i++){
292 if(parts[i] == "") continue;
293 crtPath += parts[i];
294 if(!model[parts[i]]) {
295 var virtualFolder = new qx.ui.tree.TreeFolder(parts[i]);
296 model[parts[i]] = virtualFolder;
297 crtFolder.add(virtualFolder);
298 crtFolder = virtualFolder;
299 }else{
300 crtFolder = model[parts[i]];
301 }
302 }
303 crtFolder.add(childNode);
304 }
305 },
306
307 members :
308 {
309 /**
310 * Called at applet creation. Just registers viewPane.
311 * @param viewPane {org.argeo.ria.components.ViewPane} The viewPane.
312 */
313 init : function(viewPane){
314 this.setView(viewPane);
315 this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));
316 this._amqClient = org.argeo.ria.remote.JmsClient.getInstance();
317 this._amqClient.uri = "/org.argeo.slc.webapp/amq";
318 this._amqClient.startPolling();
319 },
320
321 /**
322 *
323 */
324 load : function(){
325 this._createLayout();
326 this.getView().setViewTitle("Execution Launcher");
327 org.argeo.ria.remote.RequestManager.getInstance().addListener("reload", function(reloadEvent){
328 if(reloadEvent.getDataType()!= "agents") return ;
329 var xmlDoc = reloadEvent.getContent();
330 var nodes = org.argeo.ria.util.Element.selectNodes(xmlDoc, "//slc:slc-agent-descriptor");
331 var newTopics = {};
332 for(var i=0;i<nodes.length;i++){
333 var uuid = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "@uuid");
334 var host = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "slc:host");
335 newTopics[uuid] = host+" ("+uuid+")";
336 }
337 this.setRegisteredTopics(newTopics);
338 }, this);
339 this.addListener("changeRegisteredTopics", function(event){
340 //this._refreshTopicsSubscriptions(event);
341 this._feedSelector(event);
342 }, this);
343 var reloadHandler = function(message){
344 // Delay reload to be sure the jms was first integrated by the db, then ask the db.
345 qx.event.Timer.once(function(){
346 org.argeo.ria.event.CommandsManager.getInstance().getCommandById("reloadagents").execute();
347 }, this, 1000);
348 }
349 this._amqClient.addListener("agentregister", "topic://agent.register", reloadHandler, this);
350 this._amqClient.addListener("agentunregister", "topic://agent.unregister", reloadHandler, this);
351 reloadHandler();
352 },
353
354 addScroll : function(){
355 return false;
356 },
357
358 close : function(){
359 this._amqClient.removeListener("agentregister", "topic://agent.register");
360 this._amqClient.removeListener("agentunregister", "topic://agent.unregister");
361 this._amqClient.removeListener("modulesResponse", "topic://modulesManager.response");
362 this.setRegisteredTopics({});
363 this._amqClient.stopPolling();
364 },
365
366 /**
367 * Creates the main applet layout.
368 */
369 _createLayout : function(){
370
371 var splitPane = new qx.ui.splitpane.Pane("vertical");
372 splitPane.setDecorator(null);
373 this.add(splitPane);
374
375 this.formPane = new qx.ui.container.Composite(new qx.ui.layout.VBox(5));
376 this.scroll = new qx.ui.container.Scroll(this.formPane);
377 this.formPane.setPadding(10);
378
379 this.tree = new qx.ui.tree.Tree();
380 this.tree.setDecorator(null);
381 var dragData = {
382 "file" : {
383 "type" : ["items"],
384 "action":["move"]
385 }
386 };
387
388 var root = new org.argeo.ria.components.DynamicTreeFolder(
389 "All Tests",
390 this.self(arguments).modulesLoader,
391 "Loading Modules",
392 dragData
393 );
394 this.tree.setRoot(root);
395 root.setOpen(true);
396 this.tree.setContextMenu(org.argeo.ria.event.CommandsManager.getInstance().createMenuFromIds(["addtobatch", "reloadtree"]));
397
398 this.tree.addListener("changeSelection", function(e){
399 var viewSelection = this.getViewSelection();
400 viewSelection.setViewId("form:tree");
401 viewSelection.clear();
402 var sel = this.tree.getSortedSelection();
403 for(var i=0;i<sel.length;i++){
404 viewSelection.addNode(sel[i]);
405 }
406 }, this);
407
408 this.listPane = new qx.ui.container.Composite(new qx.ui.layout.Dock());
409 var listToolBar = new qx.ui.toolbar.ToolBar();
410 var toolGroup = new qx.ui.toolbar.Part();
411 listToolBar.add(toolGroup);
412
413 var execButton = this.getCommands()["submitform"].command.getToolbarButton();
414 toolGroup.add(execButton);
415
416 listToolBar.addSpacer();
417 listToolBar.setPaddingRight(4);
418 var delButton = this.getCommands()["removefrombatch"].command.getToolbarButton();
419 var formButton = this.getCommands()["editexecutionspecs"].command.getToolbarButton();
420 delButton.setShow("icon");
421 formButton.setShow("icon");
422 listToolBar.add(formButton);
423 listToolBar.add(delButton);
424
425 this.listPane.add(listToolBar, {edge:"north"});
426
427 var indicator = new qx.ui.core.Widget();
428 indicator.setDecorator(new qx.ui.decoration.Single().set({top:[1,"solid","#33508D"]}));
429 indicator.setHeight(0);
430 indicator.setOpacity(0.5);
431 indicator.setZIndex(100);
432 indicator.setLayoutProperties({left:-1000,top:-1000});
433 org.argeo.ria.Application.INSTANCE.getRoot().add(indicator);
434
435
436 this.list = new qx.ui.form.List();
437 this.list.setDecorator(null);
438 this.list.setSelectionMode("multi");
439 this.list.setDroppable(true);
440 this.list.setDraggable(true);
441 this.list.setContextMenu(org.argeo.ria.event.CommandsManager.getInstance().createMenuFromIds(["editexecutionspecs", "removefrombatch"]));
442
443
444 this.list.addListener("dragstart", function(e){
445 e.addType(["items"]);
446 e.addAction(["move"]);
447 },this);
448 this.list.addListener("dragend", function(e){
449 indicator.setDomPosition(-1000,-1000);
450 });
451 this.list.addListener("dragover", function(e){
452 var orig = e.getOriginalTarget();
453 var origCoords = orig.getContainerLocation();
454 indicator.setWidth(orig.getBounds().width);
455 indicator.setDomPosition(origCoords.left, origCoords.bottom);
456 });
457 this.list.addListener("drag", function(e){
458 var orig = e.getOriginalTarget();
459 var origCoords = orig.getContainerLocation();
460 indicator.setWidth(orig.getBounds().width);
461 indicator.setDomPosition(origCoords.left, origCoords.bottom);
462 });
463
464 this.list.addListener("drop", function(e){
465 var target = e.getRelatedTarget();
466 var afterItem = e.getOriginalTarget();
467 indicator.setDomPosition(-1000,-1000);
468 if(afterItem.classname != "qx.ui.form.ListItem") afterItem = null;
469 if(!target){
470 target = this.list.getSortedSelection()[0];
471 }
472 this._addFlowToBatch(target, afterItem);
473 }, this);
474 this.listPane.add(this.list, {edge:"center"});
475
476 this.list.addListener("changeSelection", function(e){
477 var viewSelection = this.getViewSelection();
478 viewSelection.setViewId("form:list");
479 viewSelection.clear();
480 var listSel = this.list.getSortedSelection();
481 for(var i=0;i<listSel.length;i++){
482 viewSelection.addNode(listSel[i]);
483 }
484 }, this);
485
486 splitPane.add(this.tree, 0);
487 splitPane.add(this.listPane, 1);
488 },
489
490 /**
491 * Adds a given ExecutionFlow to the batch
492 * @param target {mixed} The dropped target, can be a TreeFile (add) or a ListItem (reorder).
493 * @param after {qx.ui.form.ListItem} Optional list item : if set, the flow will be added as a new list item positionned after this one.
494 */
495 _addFlowToBatch : function(target, after){
496 //this.debug(target);
497 if(!target){
498 target = this.tree.getSelectedItem();
499 if(!target) return;
500 }else if(target.classname == "qx.ui.form.ListItem"){
501 if(!after) return;
502 if(after == "first") this.list.addAt(target, 0);
503 else this.list.addAfter(target, after);
504 return;
505 }
506 var executionModule = target.getUserData("executionModule");
507 var executionFlow = target.getUserData("executionFlow");
508 var batchEntry = new org.argeo.slc.ria.execution.BatchEntrySpec(executionModule, executionFlow);
509 var label = batchEntry.getLabel();
510 var icon = target.getIcon();
511 var item = new qx.ui.form.ListItem(label, icon);
512 item.addListener("dblclick", function(e){
513 this.getCommands()["editexecutionspecs"].command.execute();
514 }, this);
515 item.setUserData("batchEntrySpec", batchEntry);
516 item.setPaddingTop(1);
517 item.setPaddingBottom(2);
518 if(after){
519 if(after == "first") this.list.addAt(item, 0);
520 else this.list.addAfter(item, after);
521 }else{
522 this.list.add(item);
523 }
524 this.list.select(item);
525 if(this.getAutoOpen()){
526 this.getCommands()["editexecutionspecs"].command.execute();
527 }
528 },
529
530 /**
531 * Refresh the selector when the topics are updated.
532 * @param changeTopicsEvent {qx.event.type.DataEvent} The reload event.
533 */
534 _feedSelector : function(changeTopicsEvent){
535 var topics = changeTopicsEvent.getData();
536 var command = this.getCommands()["submitform"].command;
537 command.setEnabled(false);
538 var menu = [];
539 for(var key in topics){
540 var submenu = {"label":topics[key],"icon":"resource/slc/mime-xsl.png", "commandId":key};
541 menu.push(submenu);
542 }
543 // FAKE!!
544 if(!menu.length){
545 menu.push({"label":"Fake Agent", "icon":"resource/slc/mime-xsl.png", "commandId":"fake_agent_uuid"});
546 }
547 command.clearMenus();
548 command.setMenu(menu);
549 if(menu.length) command.setEnabled(true);
550 },
551
552
553 /**
554 * Called at execution
555 * @param agentUuid {String} The id of the target agent
556 */
557 executeBatchOnAgent : function(agentUuid){
558 var selection = this.list.getChildren();
559 if(!selection.length) return;
560 var slcExecMessage = new org.argeo.slc.ria.execution.Message();
561 for(var i=0;i<selection.length;i++){
562 var batchEntrySpec = selection[i].getUserData("batchEntrySpec");
563 slcExecMessage.addBatchEntrySpec(batchEntrySpec);
564 }
565 this._amqClient.sendMessage(
566 "topic://agent.newExecution",
567 slcExecMessage.toXml(),
568 {"slc-agentId":agentUuid}
569 );
570 // Force logs refresh right now!
571 qx.event.Timer.once(function(){
572 var command = org.argeo.ria.event.CommandsManager.getInstance().getCommandById("reloadlogs");
573 if(command){
574 command.execute();
575 }
576 }, this, 2000);
577 }
578
579 }
580 });