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