]> 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
Order logs by date descending
[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.reload();
143 },
144 command : null
145 },
146 "reloadtree" : {
147 label : "Reload Node",
148 icon : "org.argeo.slc.ria/view-refresh.png",
149 shortcut : null,
150 enabled : false,
151 menu : null,
152 toolbar : null,
153 callback : function(e) {
154 if (this.tree.isSelectionEmpty()) { return; }
155 var selected = this.tree.getSelection()[0];
156 if (selected.classname == "org.argeo.ria.components.DynamicTreeFolder") {
157 if (selected.getUserData("moduleData")) {
158 // It's a "module" node, first trigger the
159 // reloadBundle.service
160 selected.setUserData("dataModel", {});
161 selected.setEnabled(false);
162 selected.setOpen(false);
163 var moduleData = selected
164 .getUserData("moduleData");
165 var bundleService = org.argeo.slc.ria.SlcApi
166 .getReloadBundleService(
167 moduleData.name,
168 moduleData.version);
169 bundleService.addListener("completed",
170 function(response) {
171 selected.setEnabled(true);
172 selected.setOpen(true);
173 selected.reload();
174 }, this);
175 // bundleService.send();
176 // Do not send, not implemented yet, false timer
177 // instead.
178 qx.event.Timer.once(function(response) {
179 selected.setEnabled(true);
180 selected.setOpen(true);
181 selected.reload();
182 }, this, 2000);
183 } else {
184 selected.reload();
185 }
186 }
187 },
188 selectionChange : function(viewId, selection) {
189 if (viewId != "form:tree")
190 return;
191 if (!selection)
192 return;
193 if (selection.length > 1) {
194 this.setEnabled(false);
195 return;
196 }
197 var item = selection[0];
198 if (!qx.Class.isSubClassOf(qx.Class
199 .getByName(item.classname),
200 qx.ui.tree.AbstractTreeItem))
201 return;
202 this.setEnabled(false);
203 if (qx.Class.isSubClassOf(qx.Class
204 .getByName(item.classname),
205 org.argeo.ria.components.DynamicTreeFolder)) {
206 this.setEnabled(true);
207 }
208 },
209 command : null
210 }
211 }
212 }
213 },
214
215 statics : {
216
217 riaPreferences : {
218 "flowSelector.preferred.hosts" : {
219 label : "Preferred Hosts (Execution View)",
220 type : "string"
221 }
222 },
223
224 /**
225 * Static loader for the "agent" level (first level)
226 *
227 * @param folder
228 * {org.argeo.ria.components.PersistentTreeFolder} The root Tree Folder.
229 */
230 agentLoader : function(folder) {
231
232 var preferredHosts = org.argeo.ria.session.MPrefHolder.loadRiaPreferenceValue("flowSelector.preferred.hosts");
233 if(preferredHosts && preferredHosts!=""){
234 preferredHosts = preferredHosts.split(",");
235 }
236 var req = org.argeo.slc.ria.SlcApi.getListAgentsService("agents");
237 var agents = {};
238 if(folder.getState() == "loaded" && folder.getUserData("agentsMap")){
239 // Diff loading, just add new nodes.
240 agents = folder.getUserData("agentsMap");
241 var newAgents = {};
242 }
243 req.addListener("completed", function(response) {
244 var xmlDoc = response.getContent();
245 var nodes = org.argeo.ria.util.Element.selectNodes(xmlDoc,
246 "/slc:object-list/slc:slc-agent-descriptor");
247 var modulesLoader = org.argeo.slc.ria.FlowsSelectorView.modulesLoader;
248
249 for (var i = 0; i < nodes.length; i++) {
250 var uuid = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "@uuid");
251 var host = org.argeo.ria.util.Element.getSingleNodeText(nodes[i], "slc:host");
252 if(agents[uuid]){
253 newAgents[uuid] = host;
254 continue;
255 }
256 agents[uuid] = host;
257 if(newAgents) newAgents[uuid] = host;
258 var agentFolder = new org.argeo.ria.components.DynamicTreeFolder(
259 host, modulesLoader, "Loading Modules...", folder.getDragData());
260 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(agentFolder, uuid);
261 agentFolder.setPersistentTreeID(folder.getPersistentTreeID()+"_"+uuid);
262 agentFolder.setUserData("agentHost", host); // Used by bookmark system
263 agentFolder.setUserData("agentUuid", uuid);
264 if(preferredHosts && preferredHosts instanceof Array && qx.lang.Array.contains(preferredHosts, host)){
265 folder.addAtBegin(agentFolder);
266 agentFolder.setIcon("org.argeo.slc.ria/computer_bookmarked.png");
267 }else{
268 folder.add(agentFolder);
269 agentFolder.setIcon("org.argeo.slc.ria/computer.png");
270 }
271 }
272 if(newAgents){
273 // Make sure some agents should not be removed
274 for(var agentKey in agents){
275 if(!newAgents[agentKey]){
276 var node = org.argeo.slc.ria.FlowsSelectorView.findAgentNodeById(folder, agentKey);
277 if(node) folder.remove(node);
278 delete agents[agentKey];
279 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
280 if(batchView) batchView.clearBatchForAgentId(agentKey);
281 }
282 }
283 }
284 folder.setUserData("agentsMap", agents);
285 folder.setLoaded(true);
286 folder.getTree().fireEvent("changeSelection");
287 });
288 req.addListener("failed", function(response) {
289 folder.setLoaded(true);
290 });
291 req.send();
292
293 },
294
295 /**
296 * Loader for the "modules" level : takes any tree folder, currently the
297 * root folder.
298 *
299 * @param folder
300 * {org.argeo.ria.components.PersistentTreeFolder} The root folder
301 */
302 modulesLoader : function(folder) {
303 var agentId = folder.getUserData("agentUuid");
304 var req = org.argeo.slc.ria.SlcApi.getListModulesService(agentId);
305 req.addListener("completed", function(response) {
306 var descriptors = org.argeo.ria.util.Element.selectNodes(
307 response.getContent(),
308 "slc:object-list/" + org.argeo.slc.ria.execution.Module.XPATH_ROOT);
309 var mods = {};
310 for (var i = 0; i < descriptors.length; i++) {
311 var tmpModule = new org.argeo.slc.ria.execution.Module();
312 try{
313 tmpModule.setXmlNode(descriptors[i]);
314 }catch(e){
315 qx.log.Logger.error(e);
316 }
317 var name = tmpModule.getName();
318 var version = tmpModule.getVersion();
319 if (!mods[name])
320 mods[name] = [];
321 mods[name].push(tmpModule);
322 }
323 var flowLoader = org.argeo.slc.ria.FlowsSelectorView.flowLoader;
324 for (var key in mods) {
325 for (var i = 0; i < mods[key].length; i++) {
326 var module = mods[key][i];
327 var versionFolder = new org.argeo.ria.components.DynamicTreeFolder(
328 module.getLabel(), flowLoader,
329 "Loading Flows", folder.getDragData());
330 versionFolder.setUserData("moduleData", {
331 name : key,
332 version : module.getVersion()
333 });
334 versionFolder.setIcon("org.argeo.slc.ria/archive.png");
335 versionFolder.setUserData("agentUuid", agentId);
336 var sep = (module.getDescription()!=""?" - ":"");
337 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(versionFolder, key + ' (' + module.getVersion() + ')'+sep+module.getDescription());
338 // Warning, we must add it AFTER setting the user data,
339 // because of the persistent loading mechanism.
340 folder.add(versionFolder);
341 }
342 }
343 folder.setLoaded(true);
344 folder.getTree().fireEvent("changeSelection");
345 });
346 req.addListener("failed", function(response) {
347 folder.setLoaded(true);
348 });
349 req.send();
350 },
351
352 /**
353 * Loader for the "flow" level : takes a folder containing "moduleData"
354 * and create its children.
355 *
356 * @param folder
357 * {org.argeo.ria.components.PersistentTreeFolder} A Tree folder containing in the
358 * key "moduleData" of its user data a map containing the
359 * keys {name,version}
360 */
361 flowLoader : function(folder) {
362 var moduleData = folder.getUserData("moduleData");
363 var agentUuid = folder.getUserData("agentUuid");
364
365 var req = org.argeo.slc.ria.SlcApi
366 .getLoadExecutionDescriptorService(agentUuid,
367 moduleData.name, moduleData.version);
368 req.addListener("completed", function(response) {
369 var executionModule = new org.argeo.slc.ria.execution.Module();
370 try {
371 executionModule.setXmlNode(response.getContent());
372 } catch (e) {
373 this.error(e);
374 }
375 var execFlows = executionModule.getExecutionFlows();
376 for (var key in execFlows) {
377 var file = new qx.ui.tree.TreeFile(key);
378 if(execFlows[key].getDescription() != ""){
379 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(file, execFlows[key].getDescription());
380 }
381 file.setIcon("org.argeo.slc.ria/system.png");
382 var path = execFlows[key].getPath();
383 file.setUserData("executionModule", executionModule);
384 file.setUserData("executionFlow", execFlows[key]);
385 file.setUserData("agentUuid", agentUuid);
386 org.argeo.slc.ria.FlowsSelectorView.attachNodeByPath(folder, path, file, {
387 agentUuid : folder.getUserData("agentUuid")
388 });
389 folder.appendDragData(file);
390 }
391 folder.setLoaded(true);
392 folder.getTree().fireEvent("changeSelection");
393 });
394 req.addListener("failed", function(response) {
395 folder.setLoaded(true);
396 });
397 req.send();
398 },
399
400 attachToolTip : function(nodeItem, description){
401 var tt = new qx.ui.tooltip.ToolTip(description);
402 tt.setShowTimeout(0);
403 nodeItem.setToolTip(tt);
404 },
405
406 /**
407 * Parse a string path and search if there is a root node.
408 *
409 * @param rootNode
410 * {org.argeo.ria.components.DynamicTreeFolder} The parent
411 * node (containing data model)
412 * @param path
413 * {String} The path of the node to attach.
414 * @param childNode
415 * {qx.ui.tree.TreeFile} The leaf node
416 * @param userData
417 * {Map} User data to attach at all levels.
418 */
419 attachNodeByPath : function(rootNode, path, childNode, userData) {
420 if (!path || path == "" || path == "/") {
421 rootNode.add(childNode);
422 return;
423 }
424 var model = rootNode.getUserData("dataModel");
425 if (!model) {
426 model = {};
427 rootNode.setUserData("dataModel", model);
428 }
429 var parts = path.split("/");
430 var keys = qx.lang.Object.getKeys(model);
431 var crtPath = "";
432 var crtFolder = rootNode;
433 for (var i = 0; i < parts.length; i++) {
434 if (parts[i] == "")
435 continue;
436 crtPath += "/" + parts[i];
437 if (!model[crtPath]) {
438 var virtualFolder = new org.argeo.ria.components.PersistentTreeFolder(parts[i]);
439 if (userData && qx.lang.Object.getLength(userData)) {
440 for (var key in userData) {
441 virtualFolder.setUserData(key, userData[key]);
442 }
443 }
444 rootNode.appendDragData(virtualFolder);
445 model[crtPath] = virtualFolder;
446 crtFolder.add(virtualFolder);
447 crtFolder = virtualFolder;
448 } else {
449 crtFolder = model[crtPath];
450 }
451 }
452 crtFolder.add(childNode);
453 },
454
455 findAgentNodeById : function(node, agentId){
456 var nodeAgents = node.getItems();
457 for(var i=0;i<nodeAgents.length;i++){
458 if(nodeAgents[i].getUserData("agentUuid") == agentId){
459 return nodeAgents[i];
460 }
461 }
462 }
463 },
464
465 members : {
466 /**
467 * Called at applet creation. Just registers viewPane.
468 *
469 * @param viewPane
470 * {org.argeo.ria.components.ViewPane} The viewPane.
471 */
472 init : function(viewPane) {
473 this.setView(viewPane);
474 this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));
475 this.remoteNotifier = new org.argeo.ria.remote.RemoteNotifier(
476 "/org.argeo.slc.webapp/", "pollEvent.service",
477 "addEventListener.service", "removeEventListener.service");
478 this.remoteNotifier.setEventParamName("slc_eventType");
479 this.remoteNotifier.setEventXPath("/slc:slc-event");
480 this.remoteNotifier
481 .setEventTypeXPath('slc:headers/slc:header[@name="slc_eventType"]');
482 this.remoteNotifier
483 .setEventDataXPath('slc:headers/slc:header[@name="slc_agentId"]');
484 this.remoteNotifier.setAnswerStatusXPath("slc:execution-answer/slc:status");
485 this.remoteNotifier.startPolling();
486 this.UIBus = org.argeo.ria.event.UIBus.getInstance();
487 this.UIBus.registerNotifier(this.remoteNotifier);
488 },
489
490 /**
491 *
492 */
493 load : function() {
494 this._createLayout();
495 this.getView().setViewTitle("Available Scripts");
496 this.UIBus.addListener("agentRegistered", this._addAgentHandler, this);
497 this.UIBus.addListener("agentUnregistered", this._removeAgentHandler, this);
498 },
499
500 _addAgentHandler : function(agentId){
501 this.rootNode.load();
502 },
503
504 _removeAgentHandler : function(agentId){
505 var treeNode = this.self(arguments).findAgentNodeById(this.rootNode, agentId);
506 if(treeNode){
507 this.rootNode.remove(treeNode);
508 }
509 var agentsMap = this.getAgentsMap();
510 if(agentsMap[agentId]){
511 delete agentsMap[agentId];
512 }
513 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
514 if(batchView){
515 batchView.clearBatchForAgentId(agentId);
516 }
517 },
518
519 addScroll : function() {
520 return false;
521 },
522
523 close : function() {
524 this.UIBus.removeListener("agentRegistered", this._addAgentHandler, this);
525 this.UIBus.removeListener("agentUnregistered", this._removeAgentHandler, this);
526 this.remoteNotifier.stopPolling();
527 },
528
529 /**
530 *
531 * @param agentNode {qx.ui.tree.AbstractTreeItem}
532 */
533 togglePreferredHost : function(agentNode){
534 var hostName = agentNode.getUserData("agentHost");
535 var pref = this.getRiaPreferenceValue("flowSelector.preferred.hosts");
536 var prefArray = [];
537 if(pref){
538 prefArray = pref.split(",");
539 }
540 if(qx.lang.Array.contains(prefArray, hostName)){
541 qx.lang.Array.remove(prefArray, hostName);
542 agentNode.setIcon("org.argeo.slc.ria/computer.png");
543 }else{
544 prefArray.push(hostName);
545 agentNode.setIcon("org.argeo.slc.ria/computer_bookmarked.png");
546 var parent = agentNode.getParent();
547 parent.remove(agentNode);
548 parent.addAtBegin(agentNode);
549 }
550 this.setRiaPreferenceValue("flowSelector.preferred.hosts", prefArray.join(","));
551 },
552
553 /**
554 * Creates the main applet layout.
555 */
556 _createLayout : function() {
557
558 this.tree = new qx.ui.tree.Tree();
559 this.tree.setDecorator(null);
560 this.tree.setSelectionMode("multi");
561 var dragData = {
562 "file" : {
563 "type" : ["items"],
564 "action" : ["move"]
565 },
566 "folder" : {
567 "type" : ["items"],
568 "action" : ["move"]
569 }
570 };
571
572 this.rootNode = new org.argeo.ria.components.DynamicTreeFolder(
573 "Tests", this.self(arguments).agentLoader,
574 "Loading Agents", dragData);
575 this.tree.setRoot(this.rootNode);
576 this.tree.setHideRoot(true);
577 this.rootNode.setPersistentTreeID("org.argeo.slc.ria.FlowsSelector")
578 this.rootNode.setOpen(true);
579 this.tree.setContextMenu(org.argeo.ria.event.CommandsManager
580 .getInstance().createMenuFromIds(["addtobatch",
581 "reloadtree", "preferredHost"]));
582
583 this.tree.addListener("changeSelection", function(e) {
584 var viewSelection = this.getViewSelection();
585 viewSelection.setViewId("form:tree");
586 viewSelection.clear();
587 var sel = this.tree.getSortedSelection();
588 for (var i = 0; i < sel.length; i++) {
589 viewSelection.addNode(sel[i]);
590 }
591 }, this);
592
593 this.tree.addListener("dblclick", function(e){
594 var sel = this.tree.getSortedSelection();
595 if(sel && sel.length!=1) return;
596 var origin = sel[0];
597 if(origin.classname == "qx.ui.tree.TreeFile"){
598 this.setExecuteAfterAdd(true);
599 this.getCommands()["addtobatch"].command.execute();
600 }
601 }, this);
602
603 this.add(this.tree);
604 },
605
606 getAgentsMap : function(){
607 return this.rootNode.getUserData("agentsMap");
608 }
609 }
610 });