]> git.argeo.org Git - gpl/argeo-slc.git/blob - server/org.argeo.slc.ria/src/argeo-ria-lib/slc/class/org/argeo/slc/ria/FlowsSelectorView.js
755fc1d0eca7472f315714dcff097013c4eaf2d1
[gpl/argeo-slc.git] / server / org.argeo.slc.ria / src / argeo-ria-lib / slc / class / org / argeo / slc / ria / FlowsSelectorView.js
1 /**
2 * The selector view
3 *
4 */
5 qx.Class.define("org.argeo.slc.ria.FlowsSelectorView", {
6 extend : qx.ui.container.Composite,
7 implement : [org.argeo.ria.components.IView],
8 include : [org.argeo.ria.session.MPrefHolder],
9
10 construct : function() {
11 this.base(arguments);
12 this.setLayout(new qx.ui.layout.Dock());
13 },
14
15 properties : {
16 /**
17 * The viewPane inside which this applet is added.
18 */
19 view : {
20 init : null
21 },
22 viewSelection : {
23 nullable : false,
24 check : "org.argeo.ria.components.ViewSelection"
25 },
26 instanceId : {
27 init : ""
28 },
29 instanceLabel : {
30 init : ""
31 },
32 executeAfterAdd : {
33 init : false,
34 check : "Boolean"
35 },
36 /**
37 * Commands definition, see
38 * {@link org.argeo.ria.event.CommandsManager#definitions}
39 */
40 commands : {
41 init : {
42 "addtobatch" : {
43 label : "Add to batch",
44 icon : "org/argeo/slc/ria/list-add.png",
45 shortcut : null,
46 enabled : true,
47 menu : null,
48 toolbar : null,
49 callback : function(e) {
50 if (this.tree.isSelectionEmpty()) {
51 return;
52 }
53 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
54 if(!batchView) return;
55 selection = this.tree.getSelection();
56 if (selection.length > 1) {
57 for (var i = 0; i < selection.length; i++) {
58 try{
59 batchView.addFlowToBatch(selection[i], null, true);
60 }catch(e){
61 return;
62 }
63 }
64 return;
65 } else {
66 try{
67 batchView.addFlowToBatch(selection[0], null);
68 }catch(e){
69 return;
70 }
71 }
72 if(this.getExecuteAfterAdd() && batchView.getCommands()){
73 batchView.setForceClearPreference(true);
74 batchView.getCommands()["submitform"].command.execute();
75 }
76 this.setExecuteAfterAdd(false);
77 },
78 selectionChange : function(viewId, selection) {
79 if (viewId != "form:tree")
80 return;
81 if (!selection || selection.length != 1)
82 return;
83 var item = selection[0];
84 this.setEnabled(false);
85 switch (item.classname) {
86 case "qx.ui.tree.TreeFile" :
87 this.setEnabled(true);
88 break;
89 case "org.argeo.ria.components.PersistentTreeFolder" :
90 if (item.getTree() && item.getTree().getRoot() == item)
91 break;
92 this.setEnabled(true);
93 break;
94 case "org.argeo.ria.components.DynamicTreeFolder" :
95 if (item.getTree() && item.getTree().getRoot() == item)
96 break;
97 if (item.getState() == "loaded")
98 this.setEnabled(true);
99 break;
100 }
101 },
102 command : null
103 },
104 "preferredHost" : {
105 label : "Toggle 'Preferred Host'",
106 icon : "ria/bookmark.png",
107 shortcut : null,
108 enabled : true,
109 menu : null,
110 toolbar : null,
111 callback : function(e) {
112 if (this.tree.isSelectionEmpty()) {
113 return;
114 }
115 var selection = this.tree.getSelection();
116 if(selection.length != 1) return;
117 var agentNode = selection[0];
118 if(!agentNode.getUserData("agentHost")) return;
119 this.togglePreferredHost(agentNode);
120 },
121 selectionChange : function(viewId, selection) {
122 if (viewId != "form:tree")
123 return;
124 if (!selection || selection.length != 1)
125 return;
126 var item = selection[0];
127 this.setEnabled(false);
128 if(item.getUserData("agentHost")){
129 this.setEnabled(true);
130 }
131 },
132 command : null
133 },
134 "reloadfull" : {
135 label : "Reload Agents",
136 icon : "org/argeo/slc/ria/view-refresh.png",
137 shortcut : "control+h",
138 enabled : true,
139 menu : "Launcher",
140 toolbar : "list",
141 callback : function(e) {
142 this.rootNode.setState("loading");
143 this.rootNode.load();
144 },
145 command : null
146 },
147 "reloadtree" : {
148 label : "Reload Node",
149 icon : "org/argeo/slc/ria/view-refresh.png",
150 shortcut : null,
151 enabled : false,
152 menu : null,
153 toolbar : null,
154 callback : function(e) {
155 if (this.tree.isSelectionEmpty()) { return; }
156 var selected = this.tree.getSelection()[0];
157 if (selected.classname == "org.argeo.ria.components.DynamicTreeFolder") {
158 if (selected.getUserData("moduleData")) {
159 // It's a "module" node, first trigger the
160 // reloadBundle.service
161 selected.setUserData("dataModel", {});
162 selected.setEnabled(false);
163 selected.setOpen(false);
164 var moduleData = selected
165 .getUserData("moduleData");
166 var bundleService = org.argeo.slc.ria.SlcApi
167 .getReloadBundleService(
168 moduleData.name,
169 moduleData.version);
170 bundleService.addListener("completed",
171 function(response) {
172 selected.setEnabled(true);
173 selected.setOpen(true);
174 selected.reload();
175 }, this);
176 // bundleService.send();
177 // Do not send, not implemented yet, false timer
178 // instead.
179 qx.event.Timer.once(function(response) {
180 selected.setEnabled(true);
181 selected.setOpen(true);
182 selected.reload();
183 }, this, 2000);
184 } else {
185 selected.reload();
186 }
187 }
188 },
189 selectionChange : function(viewId, selection) {
190 if (viewId != "form:tree")
191 return;
192 if (!selection)
193 return;
194 if (selection.length > 1) {
195 this.setEnabled(false);
196 return;
197 }
198 var item = selection[0];
199 if (!qx.Class.isSubClassOf(qx.Class
200 .getByName(item.classname),
201 qx.ui.tree.AbstractTreeItem))
202 return;
203 this.setEnabled(false);
204 if (qx.Class.isSubClassOf(qx.Class
205 .getByName(item.classname),
206 org.argeo.ria.components.DynamicTreeFolder)) {
207 this.setEnabled(true);
208 }
209 },
210 command : null
211 }
212 }
213 }
214 },
215
216 statics : {
217
218 riaPreferences : {
219 "flowSelector.preferred.hosts" : {
220 label : "Preferred Hosts (Execution View)",
221 type : "string"
222 }
223 },
224
225 /**
226 * Static loader for the "agent" level (first level)
227 *
228 * @param folder
229 * {org.argeo.ria.components.PersistentTreeFolder} The root Tree Folder.
230 */
231 agentLoader : function(folder) {
232
233 var preferredHosts = org.argeo.ria.session.MPrefHolder.loadRiaPreferenceValue("flowSelector.preferred.hosts");
234 if(preferredHosts && preferredHosts!=""){
235 preferredHosts = preferredHosts.split(",");
236 }
237 var req = org.argeo.slc.ria.SlcApi.getListAgentsService("agents");
238 var agents = {};
239 if(folder.getUserData("agentsMap")){
240 // Diff loading, just add new nodes.
241 agents = folder.getUserData("agentsMap");
242 var newAgents = {};
243 }
244 req.addListener("completed", function(response) {
245 var xmlDoc = response.getContent();
246 var nodes = org.argeo.ria.util.Element.selectNodes(xmlDoc,
247 "/slc:object-list/slc:slc-agent-descriptor");
248 var modulesLoader = org.argeo.slc.ria.FlowsSelectorView.modulesLoader;
249
250 for (var i = 0; i < nodes.length; i++) {
251 var uuid = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "@uuid");
252 var host = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "slc:host");
253 if(agents[uuid]){
254 newAgents[uuid] = host;
255 continue;
256 }
257 agents[uuid] = host;
258 if(newAgents) newAgents[uuid] = host;
259 var agentFolder = new org.argeo.ria.components.DynamicTreeFolder(
260 host, modulesLoader, "Loading Modules...", folder.getDragData());
261 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(agentFolder, uuid);
262 agentFolder.setPersistentTreeID(folder.getPersistentTreeID()+"_"+uuid);
263 agentFolder.setUserData("agentHost", host); // Used by bookmark system
264 agentFolder.setUserData("agentUuid", uuid);
265 if(preferredHosts && preferredHosts instanceof Array && qx.lang.Array.contains(preferredHosts, host)){
266 folder.addAtBegin(agentFolder);
267 agentFolder.setIcon("org/argeo/slc/ria/computer_bookmarked.png");
268 }else{
269 folder.add(agentFolder);
270 agentFolder.setIcon("org/argeo/slc/ria/computer.png");
271 }
272 }
273 if(newAgents){
274 // Make sure some agents should not be removed
275 for(var agentKey in agents){
276 if(!newAgents[agentKey]){
277 var node = org.argeo.slc.ria.FlowsSelectorView.findAgentNodeById(folder, agentKey);
278 if(node) folder.remove(node);
279 delete agents[agentKey];
280 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
281 if(batchView) batchView.clearBatchForAgentId(agentKey);
282 }
283 }
284 }
285 folder.setUserData("agentsMap", agents);
286 folder.setLoaded(true);
287 folder.getTree().fireDataEvent("changeSelection", folder.getTree().getSelection());
288 });
289 req.addListener("failed", function(response) {
290 folder.setLoaded(true);
291 });
292 req.send();
293
294 },
295
296 /**
297 * Loader for the "modules" level : takes any tree folder, currently the
298 * root folder.
299 *
300 * @param folder
301 * {org.argeo.ria.components.PersistentTreeFolder} The root folder
302 */
303 modulesLoader : function(folder) {
304 var agentId = folder.getUserData("agentUuid");
305 var req = org.argeo.slc.ria.SlcApi.getListModulesService(agentId);
306 req.addListener("completed", function(response) {
307 var descriptors = org.argeo.ria.util.Element.selectNodes(
308 response.getContent(),
309 "slc:object-list/" + org.argeo.slc.ria.execution.Module.XPATH_ROOT);
310 var mods = {};
311 for (var i = 0; i < descriptors.length; i++) {
312 var tmpModule = new org.argeo.slc.ria.execution.Module();
313 try{
314 tmpModule.setXmlNode(descriptors[i]);
315 }catch(e){
316 qx.log.Logger.error(e);
317 }
318 var name = tmpModule.getName();
319 var version = tmpModule.getVersion();
320 if (!mods[name])
321 mods[name] = [];
322 mods[name].push(tmpModule);
323 }
324 var flowLoader = org.argeo.slc.ria.FlowsSelectorView.flowLoader;
325 for (var key in mods) {
326 for (var i = 0; i < mods[key].length; i++) {
327 var module = mods[key][i];
328 var versionFolder = new org.argeo.ria.components.DynamicTreeFolder(
329 module.getLabel(), flowLoader,
330 "Loading Flows", folder.getDragData());
331 versionFolder.setUserData("moduleData", {
332 name : key,
333 version : module.getVersion()
334 });
335 versionFolder.setIcon("org/argeo/slc/ria/archive.png");
336 versionFolder.setUserData("agentUuid", agentId);
337 var sep = (module.getDescription()!=""?" - ":"");
338 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(versionFolder, key + ' (' + module.getVersion() + ')'+sep+module.getDescription());
339 // Warning, we must add it AFTER setting the user data,
340 // because of the persistent loading mechanism.
341 folder.add(versionFolder);
342 }
343 }
344 folder.setLoaded(true);
345 folder.getTree().fireDataEvent("changeSelection", folder.getTree().getSelection());
346 });
347 req.addListener("failed", function(response) {
348 folder.setLoaded(true);
349 });
350 req.send();
351 },
352
353 /**
354 * Loader for the "flow" level : takes a folder containing "moduleData"
355 * and create its children.
356 *
357 * @param folder
358 * {org.argeo.ria.components.PersistentTreeFolder} A Tree folder containing in the
359 * key "moduleData" of its user data a map containing the
360 * keys {name,version}
361 */
362 flowLoader : function(folder) {
363 var moduleData = folder.getUserData("moduleData");
364 var agentUuid = folder.getUserData("agentUuid");
365
366 var req = org.argeo.slc.ria.SlcApi
367 .getLoadExecutionDescriptorService(agentUuid,
368 moduleData.name, moduleData.version);
369 req.addListener("completed", function(response) {
370 var executionModule = new org.argeo.slc.ria.execution.Module();
371 try {
372 executionModule.setXmlNode(response.getContent());
373 } catch (e) {
374 this.error(e);
375 }
376 var execFlows = executionModule.getExecutionFlows();
377 for (var key in execFlows) {
378 var path = execFlows[key].getPath();
379 var name = execFlows[key].getName();
380 var nodeLabel = key;
381 var sep = "\/";
382 if(name && name.indexOf(sep)>-1 && !path){
383 // Use given name to build the path.
384 // split dirname and basename
385 var parts = name.split(sep);
386 var basename = parts.pop();
387 var dirname = parts.join("/");
388 path = dirname;
389 nodeLabel = basename;
390 }
391 var file = new qx.ui.tree.TreeFile(nodeLabel);
392 if(execFlows[key].getDescription() != ""){
393 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(file, execFlows[key].getDescription());
394 }
395 file.setIcon("org/argeo/slc/ria/system.png");
396 file.setUserData("executionModule", executionModule);
397 file.setUserData("executionFlow", execFlows[key]);
398 file.setUserData("agentUuid", agentUuid);
399 org.argeo.slc.ria.FlowsSelectorView.attachNodeByPath(folder, path, file, {
400 agentUuid : folder.getUserData("agentUuid")
401 });
402 folder.appendDragData(file);
403 }
404 folder.setLoaded(true);
405 folder.getTree().fireDataEvent("changeSelection", folder.getTree().getSelection());
406 });
407 req.addListener("failed", function(response) {
408 folder.setLoaded(true);
409 });
410 req.send();
411 },
412
413 attachToolTip : function(nodeItem, description){
414 var tt = new qx.ui.tooltip.ToolTip(description);
415 tt.setShowTimeout(0);
416 nodeItem.setToolTip(tt);
417 },
418
419 /**
420 * Parse a string path and search if there is a root node.
421 *
422 * @param rootNode
423 * {org.argeo.ria.components.DynamicTreeFolder} The parent
424 * node (containing data model)
425 * @param path
426 * {String} The path of the node to attach.
427 * @param childNode
428 * {qx.ui.tree.TreeFile} The leaf node
429 * @param userData
430 * {Map} User data to attach at all levels.
431 */
432 attachNodeByPath : function(rootNode, path, childNode, userData) {
433 if (!path || path == "" || path == "/") {
434 rootNode.add(childNode);
435 return;
436 }
437 var model = rootNode.getUserData("dataModel");
438 if (!model) {
439 model = {};
440 rootNode.setUserData("dataModel", model);
441 }
442 var parts = path.split("/");
443 var keys = qx.lang.Object.getKeys(model);
444 var crtPath = "";
445 var crtFolder = rootNode;
446 for (var i = 0; i < parts.length; i++) {
447 if (parts[i] == "")
448 continue;
449 crtPath += "/" + parts[i];
450 if (!model[crtPath]) {
451 var virtualFolder = new org.argeo.ria.components.PersistentTreeFolder(parts[i]);
452 if (userData && qx.lang.Object.getLength(userData)) {
453 for (var key in userData) {
454 virtualFolder.setUserData(key, userData[key]);
455 }
456 }
457 rootNode.appendDragData(virtualFolder);
458 model[crtPath] = virtualFolder;
459 crtFolder.add(virtualFolder);
460 crtFolder = virtualFolder;
461 } else {
462 crtFolder = model[crtPath];
463 }
464 }
465 crtFolder.add(childNode);
466 },
467
468 findAgentNodeById : function(node, agentId){
469 var nodeAgents = node.getItems();
470 for(var i=0;i<nodeAgents.length;i++){
471 if(nodeAgents[i].getUserData("agentUuid") == agentId){
472 return nodeAgents[i];
473 }
474 }
475 }
476 },
477
478 members : {
479 /**
480 * Called at applet creation. Just registers viewPane.
481 *
482 * @param viewPane
483 * {org.argeo.ria.components.ViewPane} The viewPane.
484 */
485 init : function(viewPane) {
486 this.setView(viewPane);
487 this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));
488 this.remoteNotifier = new org.argeo.ria.remote.RemoteNotifier(
489 "/org.argeo.slc.webapp/", "pollEvent.service",
490 "addEventListener.service", "removeEventListener.service");
491 this.remoteNotifier.setEventParamName("slc_eventType");
492 this.remoteNotifier.setEventXPath("/slc:slc-event");
493 this.remoteNotifier
494 .setEventTypeXPath('slc:headers/slc:header[@name="slc_eventType"]');
495 this.remoteNotifier
496 .setEventDataXPath('slc:headers/slc:header[@name="slc_agentId"]');
497 this.remoteNotifier.setAnswerStatusXPath("slc:execution-answer/slc:status");
498 this.remoteNotifier.startPolling();
499 this.UIBus = org.argeo.ria.event.UIBus.getInstance();
500 this.UIBus.registerNotifier(this.remoteNotifier);
501 },
502
503 /**
504 *
505 */
506 load : function() {
507 this._createLayout();
508 this.getView().setViewTitle("Available Scripts");
509 this.UIBus.addListener("agentRegistered", this._addAgentHandler, this);
510 this.UIBus.addListener("agentUnregistered", this._removeAgentHandler, this);
511 },
512
513 _addAgentHandler : function(agentId){
514 this.rootNode.load();
515 },
516
517 _removeAgentHandler : function(agentId){
518 var treeNode = this.self(arguments).findAgentNodeById(this.rootNode, agentId);
519 if(treeNode){
520 this.rootNode.remove(treeNode);
521 }
522 var agentsMap = this.getAgentsMap();
523 if(agentsMap[agentId]){
524 delete agentsMap[agentId];
525 }
526 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
527 if(batchView){
528 batchView.clearBatchForAgentId(agentId);
529 }
530 },
531
532 addScroll : function() {
533 return false;
534 },
535
536 close : function() {
537 this.UIBus.removeListener("agentRegistered", this._addAgentHandler, this);
538 this.UIBus.removeListener("agentUnregistered", this._removeAgentHandler, this);
539 this.remoteNotifier.stopPolling();
540 },
541
542 /**
543 *
544 * @param agentNode {qx.ui.tree.AbstractTreeItem}
545 */
546 togglePreferredHost : function(agentNode){
547 var hostName = agentNode.getUserData("agentHost");
548 var pref = this.getRiaPreferenceValue("flowSelector.preferred.hosts");
549 var prefArray = [];
550 if(pref){
551 prefArray = pref.split(",");
552 }
553 if(qx.lang.Array.contains(prefArray, hostName)){
554 qx.lang.Array.remove(prefArray, hostName);
555 agentNode.setIcon("org/argeo/slc/ria/computer.png");
556 }else{
557 prefArray.push(hostName);
558 agentNode.setIcon("org/argeo/slc/ria/computer_bookmarked.png");
559 var parent = agentNode.getParent();
560 parent.remove(agentNode);
561 parent.addAtBegin(agentNode);
562 }
563 this.setRiaPreferenceValue("flowSelector.preferred.hosts", prefArray.join(","));
564 },
565
566 /**
567 * Creates the main applet layout.
568 */
569 _createLayout : function() {
570
571 this.tree = new qx.ui.tree.Tree();
572 this.tree.setDecorator(null);
573 this.tree.setSelectionMode("multi");
574 var dragData = {
575 "file" : {
576 "type" : ["items"],
577 "action" : ["move"]
578 },
579 "folder" : {
580 "type" : ["items"],
581 "action" : ["move"]
582 }
583 };
584
585 this.rootNode = new org.argeo.ria.components.DynamicTreeFolder(
586 "Tests", this.self(arguments).agentLoader,
587 "Loading Agents", dragData);
588 this.tree.setRoot(this.rootNode);
589 this.tree.setHideRoot(true);
590 this.rootNode.setPersistentTreeID("org/argeo/slc/ria.FlowsSelector")
591 this.rootNode.setOpen(true);
592 this.tree.setContextMenu(org.argeo.ria.event.CommandsManager
593 .getInstance().createMenuFromIds(["addtobatch",
594 "reloadtree", "preferredHost"]));
595
596 this.tree.addListener("changeSelection", function(e) {
597 var viewSelection = this.getViewSelection();
598 viewSelection.setViewId("form:tree");
599 viewSelection.clear();
600 var sel = this.tree.getSortedSelection();
601 for (var i = 0; i < sel.length; i++) {
602 viewSelection.addNode(sel[i]);
603 }
604 }, this);
605
606 this.tree.addListener("dblclick", function(e){
607 var sel = this.tree.getSortedSelection();
608 if(sel && sel.length!=1) return;
609 var origin = sel[0];
610 if(origin.classname == "qx.ui.tree.TreeFile"){
611 this.setExecuteAfterAdd(true);
612 this.getCommands()["addtobatch"].command.execute();
613 }
614 }, this);
615
616 this.add(this.tree);
617 },
618
619 getAgentsMap : function(){
620 return this.rootNode.getUserData("agentsMap");
621 }
622 }
623 });