]> 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
Add type attribute for ref-value
[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.getDescription(), 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 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(versionFolder, key + ' (' + module.getVersion() + ')');
328 // Warning, we must add it AFTER setting the user data,
329 // because of the persistent loading mechanism.
330 folder.add(versionFolder);
331 }
332 }
333 folder.setLoaded(true);
334 folder.getTree().fireEvent("changeSelection");
335 });
336 req.addListener("failed", function(response) {
337 folder.setLoaded(true);
338 });
339 req.send();
340 },
341
342 /**
343 * Loader for the "flow" level : takes a folder containing "moduleData"
344 * and create its children.
345 *
346 * @param folder
347 * {org.argeo.ria.components.PersistentTreeFolder} A Tree folder containing in the
348 * key "moduleData" of its user data a map containing the
349 * keys {name,version}
350 */
351 flowLoader : function(folder) {
352 var moduleData = folder.getUserData("moduleData");
353 var agentUuid = folder.getUserData("agentUuid");
354
355 var req = org.argeo.slc.ria.SlcApi
356 .getLoadExecutionDescriptorService(agentUuid,
357 moduleData.name, moduleData.version);
358 req.addListener("completed", function(response) {
359 var executionModule = new org.argeo.slc.ria.execution.Module();
360 try {
361 executionModule.setXmlNode(response.getContent());
362 } catch (e) {
363 this.error(e);
364 }
365 var execFlows = executionModule.getExecutionFlows();
366 for (var key in execFlows) {
367 var file = new qx.ui.tree.TreeFile(key);
368 if(execFlows[key].getDescription() != ""){
369 org.argeo.slc.ria.FlowsSelectorView.attachToolTip(file, execFlows[key].getDescription());
370 }
371 file.setIcon("org.argeo.slc.ria/system.png");
372 var path = execFlows[key].getPath();
373 file.setUserData("executionModule", executionModule);
374 file.setUserData("executionFlow", execFlows[key]);
375 file.setUserData("agentUuid", agentUuid);
376 org.argeo.slc.ria.FlowsSelectorView.attachNodeByPath(folder, path, file, {
377 agentUuid : folder.getUserData("agentUuid")
378 });
379 folder.appendDragData(file);
380 }
381 folder.setLoaded(true);
382 folder.getTree().fireEvent("changeSelection");
383 });
384 req.addListener("failed", function(response) {
385 folder.setLoaded(true);
386 });
387 req.send();
388 },
389
390 attachToolTip : function(nodeItem, description){
391 var tt = new qx.ui.tooltip.ToolTip(description);
392 tt.setShowTimeout(0);
393 nodeItem.setToolTip(tt);
394 },
395
396 /**
397 * Parse a string path and search if there is a root node.
398 *
399 * @param rootNode
400 * {org.argeo.ria.components.DynamicTreeFolder} The parent
401 * node (containing data model)
402 * @param path
403 * {String} The path of the node to attach.
404 * @param childNode
405 * {qx.ui.tree.TreeFile} The leaf node
406 * @param userData
407 * {Map} User data to attach at all levels.
408 */
409 attachNodeByPath : function(rootNode, path, childNode, userData) {
410 if (!path || path == "" || path == "/") {
411 rootNode.add(childNode);
412 return;
413 }
414 var model = rootNode.getUserData("dataModel");
415 if (!model) {
416 model = {};
417 rootNode.setUserData("dataModel", model);
418 }
419 var parts = path.split("/");
420 var keys = qx.lang.Object.getKeys(model);
421 var crtPath = "";
422 var crtFolder = rootNode;
423 for (var i = 0; i < parts.length; i++) {
424 if (parts[i] == "")
425 continue;
426 crtPath += "/" + parts[i];
427 if (!model[crtPath]) {
428 var virtualFolder = new org.argeo.ria.components.PersistentTreeFolder(parts[i]);
429 if (userData && qx.lang.Object.getLength(userData)) {
430 for (var key in userData) {
431 virtualFolder.setUserData(key, userData[key]);
432 }
433 }
434 rootNode.appendDragData(virtualFolder);
435 model[crtPath] = virtualFolder;
436 crtFolder.add(virtualFolder);
437 crtFolder = virtualFolder;
438 } else {
439 crtFolder = model[crtPath];
440 }
441 }
442 crtFolder.add(childNode);
443 },
444
445 findAgentNodeById : function(node, agentId){
446 var nodeAgents = node.getItems();
447 for(var i=0;i<nodeAgents.length;i++){
448 if(nodeAgents[i].getUserData("agentUuid") == agentId){
449 return nodeAgents[i];
450 }
451 }
452 }
453 },
454
455 members : {
456 /**
457 * Called at applet creation. Just registers viewPane.
458 *
459 * @param viewPane
460 * {org.argeo.ria.components.ViewPane} The viewPane.
461 */
462 init : function(viewPane) {
463 this.setView(viewPane);
464 this.setViewSelection(new org.argeo.ria.components.ViewSelection(viewPane.getViewId()));
465 this.remoteNotifier = new org.argeo.ria.remote.RemoteNotifier(
466 "/org.argeo.slc.webapp/", "pollEvent.service",
467 "addEventListener.service", "removeEventListener.service");
468 this.remoteNotifier.setEventParamName("slc_eventType");
469 this.remoteNotifier.setEventXPath("/slc:slc-event");
470 this.remoteNotifier
471 .setEventTypeXPath('slc:headers/slc:header[@name="slc_eventType"]');
472 this.remoteNotifier
473 .setEventDataXPath('slc:headers/slc:header[@name="slc_agentId"]');
474 this.remoteNotifier.setAnswerStatusXPath("slc:execution-answer/slc:status");
475 this.remoteNotifier.startPolling();
476 this.UIBus = org.argeo.ria.event.UIBus.getInstance();
477 this.UIBus.registerNotifier(this.remoteNotifier);
478 },
479
480 /**
481 *
482 */
483 load : function() {
484 this._createLayout();
485 this.getView().setViewTitle("Available Scripts");
486 this.UIBus.addListener("agentRegistered", this._addAgentHandler, this);
487 this.UIBus.addListener("agentUnregistered", this._removeAgentHandler, this);
488 },
489
490 _addAgentHandler : function(agentId){
491 this.rootNode.load();
492 },
493
494 _removeAgentHandler : function(agentId){
495 var treeNode = this.self(arguments).findAgentNodeById(this.rootNode, agentId);
496 if(treeNode){
497 this.rootNode.remove(treeNode);
498 }
499 var agentsMap = this.getAgentsMap();
500 if(agentsMap[agentId]){
501 delete agentsMap[agentId];
502 }
503 var batchView = org.argeo.ria.components.ViewsManager.getInstance().getViewPaneById("batch").getContent();
504 if(batchView){
505 batchView.clearBatchForAgentId(agentId);
506 }
507 },
508
509 addScroll : function() {
510 return false;
511 },
512
513 close : function() {
514 this.UIBus.removeListener("agentRegistered", this._addAgentHandler, this);
515 this.UIBus.removeListener("agentUnregistered", this._removeAgentHandler, this);
516 this.remoteNotifier.stopPolling();
517 },
518
519 /**
520 *
521 * @param agentNode {qx.ui.tree.AbstractTreeItem}
522 */
523 togglePreferredHost : function(agentNode){
524 var hostName = agentNode.getUserData("agentHost");
525 var pref = this.getRiaPreferenceValue("flowSelector.preferred.hosts");
526 var prefArray = [];
527 if(pref){
528 prefArray = pref.split(",");
529 }
530 if(qx.lang.Array.contains(prefArray, hostName)){
531 qx.lang.Array.remove(prefArray, hostName);
532 agentNode.setIcon("org.argeo.slc.ria/computer.png");
533 }else{
534 prefArray.push(hostName);
535 agentNode.setIcon("org.argeo.slc.ria/computer_bookmarked.png");
536 var parent = agentNode.getParent();
537 parent.remove(agentNode);
538 parent.addAtBegin(agentNode);
539 }
540 this.setRiaPreferenceValue("flowSelector.preferred.hosts", prefArray.join(","));
541 },
542
543 /**
544 * Creates the main applet layout.
545 */
546 _createLayout : function() {
547
548 this.tree = new qx.ui.tree.Tree();
549 this.tree.setDecorator(null);
550 this.tree.setSelectionMode("multi");
551 var dragData = {
552 "file" : {
553 "type" : ["items"],
554 "action" : ["move"]
555 },
556 "folder" : {
557 "type" : ["items"],
558 "action" : ["move"]
559 }
560 };
561
562 this.rootNode = new org.argeo.ria.components.DynamicTreeFolder(
563 "Tests", this.self(arguments).agentLoader,
564 "Loading Agents", dragData);
565 this.tree.setRoot(this.rootNode);
566 this.tree.setHideRoot(true);
567 this.rootNode.setPersistentTreeID("org.argeo.slc.ria.FlowsSelector")
568 this.rootNode.setOpen(true);
569 this.tree.setContextMenu(org.argeo.ria.event.CommandsManager
570 .getInstance().createMenuFromIds(["addtobatch",
571 "reloadtree", "preferredHost"]));
572
573 this.tree.addListener("changeSelection", function(e) {
574 var viewSelection = this.getViewSelection();
575 viewSelection.setViewId("form:tree");
576 viewSelection.clear();
577 var sel = this.tree.getSortedSelection();
578 for (var i = 0; i < sel.length; i++) {
579 viewSelection.addNode(sel[i]);
580 }
581 }, this);
582
583
584 this.add(this.tree);
585 },
586
587 getAgentsMap : function(){
588 return this.rootNode.getUserData("agentsMap");
589 }
590 }
591 });