http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js new file mode 100644 index 0000000..fca90b3 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js @@ -0,0 +1,272 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import Ember from 'ember'; +import { Coordinator } from '../coordinator/coordinator'; + +var CoordinatorXmlImporter= Ember.Object.extend({ + x2js : new X2JS(), + importCoordinator (xml){ + var coordinatorJson = this.get("x2js").xml_str2json(xml); + return this.processCoordinatorXML(coordinatorJson); + }, + createNewCoordinator(){ + return Coordinator.create({ + workflow : { + appPath : '', + configuration :{ + property : Ember.A([]) + } + }, + frequency : { + type : '', + value : '' + }, + start : { + value : '', + displayValue : '', + type : 'date' + }, + end : { + value : '', + displayValue : '', + type : 'date' + }, + timezone : '', + datasets : Ember.A([]), + dataInputs : Ember.A([]), + dataOutputs : Ember.A([]), + dataInputType : 'simple', + parameters : { + configuration :{ + property : Ember.A([]) + } + }, + controls : Ember.A([]) + }); + }, + processCoordinatorXML(coordinatorJson){ + var coordinatorApp = coordinatorJson["coordinator-app"]; + var coordinator = this.createNewCoordinator(); + coordinator.name = coordinatorApp._name; + var frequency = coordinatorApp._frequency; + if(frequency.startsWith('${coord:')){ + coordinator.frequency.type = frequency.substring(frequency.indexOf(':')+1, frequency.indexOf('(')); + coordinator.frequency.value = frequency.substring(frequency.indexOf('(')+1, frequency.indexOf(')')); + }else{ + coordinator.frequency.type = 'cron'; + coordinator.frequency.value = frequency; + } + coordinator.start = this.extractDateField(coordinatorApp._start); + coordinator.end = this.extractDateField(coordinatorApp._end); + coordinator.timezone = coordinatorApp._timezone; + this.extractDataSets(coordinatorApp, coordinator); + if(coordinatorApp['input-events'] && coordinatorApp['input-events']['data-in']){ + coordinator.dataInputType = 'simple'; + this.extractInputEvents(coordinatorApp, coordinator); + }else{ + coordinator.dataInputType = 'logical'; + coordinator.supportsConditionalDataInput = true; + this.extractLogicalInputEvents(coordinatorApp, coordinator); + } + this.extractOutputEvents(coordinatorApp, coordinator); + this.extractAction(coordinatorApp, coordinator); + this.extractParameters(coordinatorApp, coordinator); + this.extractControls(coordinatorApp, coordinator); + return coordinator; + }, + extractDateField(value){ + var dateField = {}; + var date = new Date(value); + dateField.value = value; + if(isNaN(date.getTime())){ + dateField.displayValue = value; + dateField.type = 'expr'; + }else{ + dateField.type = 'date'; + var utcDate = new Date(date.getTime() + date.getTimezoneOffset()*60*1000); + dateField.displayValue = moment(utcDate).format("MM/DD/YYYY hh:mm A"); + } + return dateField; + }, + extractDataSet(dataset){ + var dataSetJson = { + name : dataset._name, + frequency : {}, + initialInstance :this.extractDateField( dataset['_initial-instance']), + timezone : dataset._timezone + }; + var frequency = dataset._frequency; + if(frequency.startsWith('${coord:')){ + dataSetJson.frequency.type = frequency.substring(frequency.indexOf(':')+1, frequency.indexOf('(')); + dataSetJson.frequency.value = frequency.substring(frequency.indexOf('(')+1, frequency.indexOf(')')); + }else{ + dataSetJson.frequency.type = 'cron'; + dataSetJson.frequency.value = frequency; + } + dataSetJson["uriTemplate"] = dataset['uri-template']; + if (dataset['done-flag']){ + dataSetJson.doneFlag = dataset['done-flag']; + } + return dataSetJson; + }, + extractDataSets(coordinatorApp, coordinator){ + if (coordinatorApp.datasets && coordinatorApp.datasets.dataset){ + if(Array.isArray(coordinatorApp.datasets.dataset)) { + coordinatorApp.datasets.dataset.forEach(function(dataset){ + coordinator.datasets.push(this.extractDataSet(dataset)); + }, this); + }else{ + coordinator.datasets.push(this.extractDataSet(coordinatorApp.datasets.dataset)); + } + } + }, + extractDataInput(datain){ + var datainJson = { + name : datain._name, + dataset : datain._dataset + }; + if (datain.instance && datain.instance.length>0){ + datainJson.instances = Ember.A([]); + if(Array.isArray(datain.instance)) { + datain.instance.forEach(function(instance){ + datainJson.instances.pushObject(this.extractDateField(instance)); + }, this); + }else{ + datainJson.instances.pushObject(this.extractDateField(datain.instance)); + } + datainJson.isList = true; + }else if (datain["start-instance"] && ["end-instance"]){ + datainJson.start = this.extractDateField(datain["start-instance"]); + datainJson.end = this.extractDateField(datain["end-instance"]); + datainJson.isList = false; + } + return datainJson; + }, + extractInputEvents(coordinatorApp, coordinator){ + if(Array.isArray(coordinatorApp['input-events']['data-in'])){ + coordinatorApp['input-events']['data-in'].forEach(function(datain){ + coordinator.dataInputs.push(this.extractDataInput(datain)); + }, this); + }else{ + coordinator.dataInputs.push(this.extractDataInput(coordinatorApp['input-events']['data-in'])); + } + }, + extractLogicalInputEvents(coordinatorApp, coordinator){ + var conditionJson = coordinatorApp['input-events']; + var condition = {}; + coordinator.conditionalDataInput = condition; + Object.keys(conditionJson).forEach((key)=>{ + condition.operator = key; + this.parseConditionTree(conditionJson[key], condition); + }, this); + }, + extractDataInputOperand(operandJson){ + var operand = {}; + operand.name = operandJson._name; + operand.type = 'dataInput'; + operand.dataset = operandJson._dataset; + if(operandJson._min) { + operand.min = operandJson._min; + } + if(operandJson._wait) { + operand.wait = operandJson._wait; + } + return operand; + }, + parseConditionTree(conditionJson, condition) { + condition.name = conditionJson._name; + condition.operands = Ember.A([]); + Object.keys(conditionJson).forEach( (key) => { + var operandsJson = conditionJson[key]; + if(key === 'data-in') { + if(Array.isArray(operandsJson) ) { + operandsJson.forEach((json) => { + condition.operands.pushObject(this.extractDataInputOperand(json)); + }, this); + }else{ + condition.operands.pushObject(this.extractDataInputOperand(operandsJson)); + } + }else if(key !== '_name') { + var operand = {}; + operand.operator = key; + operand.type = 'condition'; + condition.operands.pushObject(operand); + this.parseConditionTree(operandsJson, operand); + } + }, this); + }, + extractDataOutput(dataOutJson){ + return { + dataset:dataOutJson._dataset, + name:dataOutJson._name, + instance:this.extractDateField(dataOutJson.instance) + }; + }, + extractOutputEvents(coordinatorApp, coordinator){ + if (coordinatorApp['output-events'] && coordinatorApp['output-events']['data-out']){ + var dataOutputsJson = coordinatorApp["output-events"]["data-out"]; + if(Array.isArray(dataOutputsJson)){ + dataOutputsJson.forEach(function(dataOutJson){ + coordinator.dataOutputs.pushObject(this.extractDataOutput(dataOutJson)); + }, this); + }else{ + coordinator.dataOutputs.pushObject(this.extractDataOutput(dataOutputsJson)); + } + } + }, + extractAction(coordinatorApp, coordinator){ + var actionJson = coordinatorApp['action']['workflow']; + coordinator.workflow.appPath = actionJson['app-path']; + if(actionJson.configuration && actionJson.configuration.property){ + if(Array.isArray(actionJson.configuration.property)){ + actionJson.configuration.property.forEach(function(prop){ + coordinator.workflow.configuration.property.push(this.extractConfigProperty(prop)); + }, this); + }else{ + coordinator.workflow.configuration.property.push(this.extractConfigProperty(actionJson.configuration.property)); + } + + } + }, + extractConfigProperty(propJson){ + return {"name" : propJson.name, "value" : propJson.value}; + }, + extractParameters(coordinatorApp, coordinator){ + var paramJson = coordinatorApp['parameters']; + if(!paramJson) { + return; + } + if(paramJson.configuration && paramJson.configuration.property){ + if(Array.isArray(paramJson.configuration.property)){ + paramJson.configuration.property.forEach(function(prop){ + coordinator.parameters.configuration.property.push(this.extractConfigProperty(prop)); + }, this); + }else{ + coordinator.parameters.configuration.property.push(this.extractConfigProperty(paramJson.configuration.property)); + } + } + }, + extractControls(coordinatorApp, coordinator) { + var controls = coordinatorApp["controls"]; + if(controls && Object.keys(controls).length > 0){ + Object.keys(controls).forEach((controlName)=>{ + coordinator.controls.pushObject({'name':controlName, 'value':controls[controlName]}); + }, this); + } + } +}); +export { CoordinatorXmlImporter };
http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js new file mode 100644 index 0000000..58396d7 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js @@ -0,0 +1,22 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import Ember from 'ember'; +var Coordinator = Ember.Object.extend({ + +}); +export {Coordinator}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js new file mode 100644 index 0000000..086916f --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js @@ -0,0 +1,348 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import Ember from 'ember'; +import CytoscapeStyles from '../domain/cytoscape-style'; +var CytoscapeRenderer= Ember.Object.extend({ + currentCyNode: null, + staticNodes: ['start', 'end', 'join', 'placeholder'], + dataNodes: [], + cyOverflow: {}, + cy: null, + layoutConfigs: { name: 'dagre', fit: false, edgeSep: 100 }, + _initCY(settings){ + this.get("context").$('#'+this.id).height(settings.canvasHeight); + this.cy = cytoscape({ + container: this.get("context").$('#'+this.id), + elements: [], + style: CytoscapeStyles.style, + layout: this.get("layoutConfigs") + }); + + // the default values of each option are outlined below: + var defaults = { + zoomFactor: 2.0, // zoom factor per zoom tick + minZoom: 0.1, // min zoom level + maxZoom: 10, // max zoom level + + // icon class names + sliderHandleIcon: 'fa fa-minus', + zoomInIcon: 'fa fa-plus', + zoomOutIcon: 'fa fa-minus', + resetIcon: 'fa fa-expand' + }; + + this.cy.panzoom( defaults ); + //this.cy.center(); + this.cy.pan({x:200,y:50}); + this._addEvents(this.cy); + var self = this; + this.get("context").$('.overlay-transition-content').popover({ + html : true, + title : "Add Node <button type='button' class='close'>×</button>", + placement: 'right', + trigger : 'focus', + content : function(){ + return self.get("context").$('#workflow-actions').html(); + } + }); + + this.get("context").$("#cyRenderer").on('click','.popover .close',function(){ + this.get("context").$('.popover').popover('hide'); + }.bind(this)); + }, + _setCyOverflow() { + Ember.set(this.get("cyOverflow"), "overflown", this.cy.elements().renderedBoundingBox().y2 > this.cy.height()); + }, + _getShape(nodeType) { + switch(nodeType) { + case 'start' : + case 'end' : + case 'kill' : + case 'placeholder' : + return 'ellipse'; + case 'action' : + return 'roundrectangle'; + case 'fork' : + case 'join' : + return 'rectangle'; + case 'decision' : + return 'diamond'; + default : + return 'star'; + } + }, + + _getCyDataNodes(workflow){ + this.get('dataNodes').clear(); + var self=this; + workflow.nodeVisitor.process(workflow.startNode, function(node) { + if (node.type === 'kill') { + return; + } + self.get('dataNodes').pushObject({ + data: { + id: node.id, name: node.name, type: node.type, + shape: self._getShape(node.type), + node: node + }, + dataNodeName: Ember.computed.alias('data.node.name') + }); + if (node.transitions.length > 0) { + node.transitions.forEach(function(transition){ + if (transition.isOnError()){ + return; + } + self.get('dataNodes').pushObject( + { + data: { + id: transition.sourceNodeId + '_to_' + transition.targetNode.id, + source:transition.sourceNodeId, + target: transition.targetNode.id, + transition: transition, + transitionCount: node.getOkTransitionCount() + } + } + ); + }); + } + }); + }, + + _showNodeEditor(node, nodeObj){ + if (nodeObj && this.get("currentCyNode") && (nodeObj.data().id === this.get("currentCyNode").data().id)) { + if (this.staticNodes.contains(node.data().type)) { + return; + } + this.get("context").$("#"+ node.data().id + " :input").show(); + this.get("context").$("#"+ node.data().id + " :input").css({ + top: nodeObj.renderedPosition().y - (nodeObj.outerHeight()/2), + left: nodeObj.renderedPosition().x - (nodeObj.outerWidth()/2) + }); + } + this.set("currentCyNode", nodeObj); + }, + + _showNodeTooltip(event){ + var node = event.cyTarget; + var nodeObj = this.cy.$('#' + node.id()); + if (this.staticNodes.contains(node.data().type)) { + return; + } + this.get("context").$(".overlay-node-label").css({ + top: nodeObj.renderedPosition().y - (nodeObj.outerHeight() - ((node.data().type === 'decision')?20:0)), + left: nodeObj.renderedPosition().x + (nodeObj.outerWidth()/2 - 30) + }); + this.get("context").$(".overlay-node-label").text(node.data().node.name); + this.get("context").$(".overlay-node-label").show(); + }, + + _addEvents(cy){ + cy.on('pan', function() { + this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide(); + this.get("context").$(".overlay-transition-content").hide(); + this._setCyOverflow(); + }.bind(this)); + + cy.on('click', function(event) { + if (event.cyTarget === cy) { + this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide(); + this.get("context").$(".overlay-transition-content").hide(); + } + }.bind(this)); + + cy.on('mousemove', 'node', function(event) { + event.cyTarget.css({'border-color': '#5bb75b'}); + this.get("context").actionInfo(event.cyTarget.data().node); + this._showNodeTooltip(event); + }.bind(this)); + + cy.on('mouseout', 'node',function(event) { + event.cyTarget.css({'border-color': '#ABABAB'}); + this.get("context").$(".overlay-node-label").hide(); + }.bind(this)); + + cy.on('mousemove', 'edge', function(event) { + event.cyTarget.css({'line-color': '#5bb75b', 'target-arrow-color': '#5bb75b'}); + }.bind(this)); + + cy.on('mouseout', 'edge',function(event) { + event.cyTarget.css({'line-color': '#ABABAB', 'target-arrow-color': '#ABABAB'}); + }.bind(this)); + + cy.on('click', 'node', function(event) { + this.get("context").$(".overlay-node-actions span").hide(); + this.get("context").$(".overlay-transition-content").hide(); + var node = event.cyTarget; + var nodeObj = cy.$('#' + node.id()); + this._showNodeEditor(node, nodeObj); + if (!(node.data().type === 'start' || node.data().type === 'end' || node.data().type === 'placeholder')) { + this.get("context").$(".overlay-node-actions, .overlay-trash-icon").show(); + } + if (node.data().type === 'action' || node.data().type === 'decision') { + this.get("context").$(".overlay-settings-icon").show(); + } + if (node.data().type === 'action') { + this.get("context").$(".overlay-copy-icon").show(); + this.get("context").$(".overlay-cut-icon").show(); + if(this.get('context').get('clipboard')){ + this.get("context").$(".overlay-paste-icon").show(); + } + } + if (node.data().type === 'fork' || node.data().type === 'decision') { + this.get("context").$(".overlay-fork-icon").show(); + } + this.get("context").$(".overlay-node-actions").css({ + top: nodeObj.renderedPosition().y - (nodeObj.outerHeight()) + 20, + left: nodeObj.renderedPosition().x + (nodeObj.outerWidth()/3) + 50 + }); + this.get("context").$(".overlay-trash-icon, .overlay-fork-icon, .overlay-settings-icon, .overlay-copy-icon, .overlay-paste-icon, .overlay-cut-icon").data("node", node.data().node); + }.bind(this)); + + cy.on('click', 'edge', function(event) { + this.get("context").$(".decision-condition-label").hide(); + this.get("context").$(".overlay-transition-content").hide(); + this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide(); + this.get("context").$(".overlay-transition-content").show(); + this.get("context").$(".overlay-transition-content").css({ + top: event.originalEvent.offsetY + 10, + left: event.originalEvent.offsetX + 15 + }); + if (event.cyTarget.data().transitionCount>1){ + this.get("context").$(".overlay-trash-transition-icon").show(); + }else{ + this.get("context").$(".overlay-trash-transition-icon").hide(); + } + this.get("context").$(".overlay-transition-content").data("transition",event.cyTarget.data().transition); + + if (event.cyTarget.data().transition && event.cyTarget.data().transition.condition) { + this.get("context").$(".decision-condition-body").html(event.cyTarget.data().transition.condition); + this.get("context").$(".decision-condition-label").css({ + top: event.originalEvent.offsetY, + left: event.originalEvent.offsetX + 10 + }); + this.get("context").$(".decision-condition-label").show(); + } + }.bind(this)); + + this.get("context").$('.overlay-plus-icon').off('click'); + this.get("context").$('.overlay-plus-icon').on('click',function(){ + this.get("context").$(".overlay-transition-content").popover("show"); + this.get("context").set('popOverElement', this.get("context").$('.overlay-transition-content')); + this.get("context").setCurrentTransition(this.get("context").$(".overlay-transition-content").data("transition")); + Ember.run.later(this, function() { + this.get("context").$('.overlay-transition-content').hide(); + }, 1000); + }.bind(this)); + + this.get("context").$('.overlay-trash-transition-icon').off('click'); + this.get("context").$('.overlay-trash-transition-icon').on('click',function(){ + this.get("context").deleteTransition(this.get("context").$(".overlay-transition-content").data("transition")); + this.get("context").$('.overlay-transition-content').hide(); + }.bind(this)); + + this.get("context").$('.overlay-trash-icon i').off('click'); + this.get("context").$('.overlay-trash-icon i').on('click',function(){ + this.get("context").deleteWorkflowNode(this.get("context").$(".overlay-trash-icon").data("node")); + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + + this.get("context").$('.overlay-copy-icon i').off('click'); + this.get("context").$('.overlay-copy-icon i').on('click',function(){ + this.get("context").copyNode(this.get("context").$(".overlay-copy-icon").data("node")); + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + + this.get("context").$('.overlay-paste-icon i').off('click'); + this.get("context").$('.overlay-paste-icon i').on('click',function(){ + this.get("context").replaceNode(this.get("context").$(".overlay-paste-icon").data("node")); + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + + this.get("context").$('.overlay-cut-icon i').off('click'); + this.get("context").$('.overlay-cut-icon i').on('click',function(){ + this.get("context").cutNode(this.get("context").$(".overlay-cut-icon").data("node")); + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + + this.get("context").$('.overlay-fork-icon i').off('click'); + this.get("context").$('.overlay-fork-icon i').on('click',function(){ + var node = this.get("context").$(".overlay-fork-icon").data("node"); + + if (node.isDecisionNode()) { + this.get("context").openDecisionEditor(this.get("context").$(".overlay-fork-icon").data("node")); + this.get("context").$("#selector-content").css({ + top: this.get("currentCyNode").renderedPosition().y - (this.get("currentCyNode").outerHeight()), + left: this.get("currentCyNode").renderedPosition().x + (this.get("currentCyNode").outerWidth()/2) + }); + } else if (node.isForkNode()) { + this.get("context").addWorkflowBranch(this.get("context").$(".overlay-fork-icon").data("node")); + } + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + + this.get("context").$('.overlay-settings-icon i').off('click'); + this.get("context").$('.overlay-settings-icon i').on('click',function(){ + this.get("context").openWorkflowEditor(this.get("context").$(".overlay-settings-icon").data("node")); + this.get("context").$('.overlay-node-actions').hide(); + }.bind(this)); + }, + + renderWorkflow(workflow){ + this._getCyDataNodes(workflow); + this.cy.$('node').remove(); + this.cy.add(this.get('dataNodes')); + this.cy.layout(this.get("layoutConfigs")); + this._setCyOverflow(); + }, + + initRenderer(callback, settings){ + this.context=settings.context; + this.dataNodes=settings.dataNodes; + this.cyOverflow=settings.cyOverflow; + this._initCY(settings); + callback(); + }, + reset(){ + + }, + resetLayout() { + this.cy.layout(); + }, + refresh(){ + + }, + onDidUpdate(){ + return true; + }, + cleanup(){ + }, + resize(){ + if (this.cy){ + Ember.run.later(this, function() { + this.cy.resize(); + },50); + } + }, + getBottomPosition() { + return { + top: this.get("context").$('#'+this.id).offset().top + this.get("context").$('#'+this.id).height, + left: this.get("context").$('#'+this.id).offset().left + 100 + }; + } +}); +export {CytoscapeRenderer}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js new file mode 100644 index 0000000..92820f9 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; +var defaultNodeColor = '#fff'; +var actionNodeColor = '#f5f5f5'; +export default Ember.Object.create({ + style: [ + { + selector: 'node', + style: { + shape: 'data(shape)', + 'background-color': defaultNodeColor, + 'border-width': 1, + 'border-color': '#ABABAB', + //'text-margin-x': 10, + label: function(target) { + if (!target.data().node.name) { + return ""; + } else if (target.data().node.name.length>12){ + return target.data().node.name.slice(0, 12)+"..."; + } else{ + return target.data().node.name; + } + }, + 'text-valign': 'center', + 'font-size': 14, + height: 40, + width: 40 + } + }, + { + selector: 'node[type = "fork"]', + style: { + 'background-image': 'assets/sitemap.png', + 'background-position-x': 10, + width: 150 + } + }, + { + selector: 'node[type = "join"]', + style: { + 'background-image': 'assets/join.png', + label: '', + width: 80 + } + }, + { + selector: 'node[type = "decision"]', + style: { + height: 60, + width: 120 + } + }, + { + selector: 'node[type = "start"]', + style: { + 'background-image': 'assets/play.png', + label: '' + } + }, + { + selector: 'node[type = "end"]', + style: { + 'background-image': 'assets/stop.png', + label: '' + } + }, + { + selector: 'node[type = "placeholder"]', + style: { + width: 1, + height: 1, + label: '' + } + }, + { + selector: 'node[type = "action"]', + style: { + 'background-color': actionNodeColor, + width: 150 + } + }, + { + selector: 'edge', + style: { + 'curve-style': 'bezier', + 'target-arrow-shape': function(target){ + if (target.data().transition && target.data().transition.getTargetNode(false) && !target.data().transition.getTargetNode(false).isPlaceholder()) { + return "triangle"; + }else{ + return "none"; + } + }, + width: 1, + 'font-size': 12, + label: function(target) { + if (!target.data().transition || !target.data().transition.condition) { + return ""; + }else if (target.data().transition.condition.length>5){ + return target.data().transition.condition.slice(0, 5)+"..."; + }else{ + return target.data().transition.condition; + } + } + } + } + ] +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js index e208f83..b7121f4 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js @@ -17,13 +17,13 @@ import Ember from 'ember'; var DefaultLayoutManager= Ember.Object.extend({ - doDagreLayout(nodes,edges){ + doDagreLayout(component, nodes,edges){ var g = new dagre.graphlib.Graph(); g.setGraph({rankdir:"TB", nodesep:100,edgesep:200,marginx:40,ranksep:130}); g.setDefaultEdgeLabel(function() { return {}; }); for (var i = 0; i < nodes.length; i++) { - var n = Ember.$(nodes[i]); + var n = component.$(nodes[i]); g.setNode(n.attr("id"), {width: n.width(), height: n.height()}); } @@ -35,13 +35,13 @@ var DefaultLayoutManager= Ember.Object.extend({ return g; }, doLayout(component,nodes,edges){ - var g=this.doDagreLayout(nodes,edges); + var g=this.doDagreLayout(component, nodes,edges); g.nodes().forEach(function(v) { try{ var nodeWidth=component.$("#" + v).width(); var displacement=150-Math.floor(nodeWidth/2); - Ember.$("#" + v).css("left", g.node(v).x+displacement + "px"); - Ember.$("#" + v).css("top",g.node(v).y+ "px"); + component.$("#" + v).css("left", g.node(v).x+displacement + "px"); + component.$("#" + v).css("top",g.node(v).y+ "px"); }catch(err){ } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js index 0566e06..c770fb0 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js @@ -18,22 +18,65 @@ import Ember from 'ember'; var FindNodeMixin= Ember.Mixin.create({ findNodeById(startNode,id){ - - return this.findNodeByIdInternal(startNode,id); + return this._findNodeById(startNode,id); + }, + findTransition(startNode,sourceId,targetId){ + return this._findTransition(startNode,sourceId,targetId); + }, + _findTransition(node,sourceId,targetId){ + if (!node.transitions){ + return null; + } + var res; + for (var i = 0; i < node.transitions.length; i++) { + var tran= node.transitions[i]; + if (node.id===sourceId && tran.getTargetNode(false).id===targetId){ + res=tran; + }else{ + res=this._findTransition(tran.getTargetNode(false),sourceId,targetId); + } + if (res){ + break; + } + } + return res; + }, + findTransitionTo(startNode,nodeid){ + return this._findTransitionTo(startNode,nodeid); + }, + _findTransitionTo(node,nodeid){ + if (!node.transitions){ + return null; + } + var res; + for (var i = 0; i < node.transitions.length; i++) { + var tran= node.transitions[i]; + if (tran.getTargetNode(false).id===nodeid){ + res=tran; + }else{ + res=this._findTransitionTo(tran.getTargetNode(false),nodeid); + } + if (res){ + break; + } + } + return res; }, - findNodeByIdInternal(node,id){ + _findNodeById(node,id){ var self=this; if (node.get("id")===id){ return node; }else{ if (node.transitions){ + var res; for (var i = 0; i < node.transitions.length; i++) { var transition=node.transitions[i]; - var result=self.findNodeByIdInternal(transition.getTargetNode(true),id); - if (result){ - return result; + res= self._findNodeById(transition.getTargetNode(false),id); + if (res){ + break; } } + return res; }else{ return null; } @@ -63,7 +106,7 @@ var FindNodeMixin= Ember.Mixin.create({ for(var i =0; i< nxtPath.length; i++){ currNode = nxtPath[i]; do { - if(this.insertUniqueNodes(currNode, nodes) && currNode){ + if(this._insertUniqueNodes(currNode, nodes) && currNode){ nodes.push(currNode); } var nodesList = currNode.getTargets(); @@ -74,7 +117,7 @@ var FindNodeMixin= Ember.Mixin.create({ if(tmp.length){ nodes = nodes.concat(tmp); } - } else if(this.insertUniqueNodes(nodesList[j], nodes) && nodesList[j]){ + } else if(this._insertUniqueNodes(nodesList[j], nodes) && nodesList[j]){ nodes.push(nodesList[j]); currNode = nodesList[j]; } else { @@ -91,7 +134,7 @@ var FindNodeMixin= Ember.Mixin.create({ } return nodes; }, - insertUniqueNodes(currNode, nodes){ + _insertUniqueNodes(currNode, nodes){ if(nodes.indexOf(currNode) > -1){ } else { if (!( currNode.isKillNode() || currNode.isPlaceholder() || currNode.isJoinNode() || currNode.isDecisionEnd())){ @@ -99,5 +142,57 @@ var FindNodeMixin= Ember.Mixin.create({ } } }, + _findCommonTargetNodeId(node){ + var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0; + for(var i =0; i< decPath.length; i++){ + var currNode = decPath[i]; + do { + if(nodeIds.hasOwnProperty(currNode.get("id"))){ + nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1; + } else { + nodeIds[currNode.get("id")] = 1; + } + if(currNode.get("id") === "node-end"){ + break; + } + currNode = currNode.getTargets()[0]; + } while(currNode && currNode.get("id")); + } + for(var j in nodeIds){ + if(tempId < nodeIds[j]){ + targ = j; + tempId = nodeIds[j]; + } + } + return targ; + }, + _findCommonTargetNode(node){ + var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0; + for(var i =0; i< decPath.length; i++){ + var currNode = decPath[i]; + do { + if(nodeIds.hasOwnProperty(currNode.get("id"))){ + nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1; + } else { + nodeIds[currNode.get("id")] = 1; + } + if(currNode.get("id") === "node-end"){ + break; + } + currNode = currNode.getTargets()[0]; + } while(currNode && currNode.get("id")); + } + for(var j in nodeIds){ + if(tempId < nodeIds[j]){ + targ = j; + tempId = nodeIds[j]; + } + } + return targ; + }, + findCommonTargetNode(startNode,node){ + var commonTargetId=this._findCommonTargetNodeId(node); + return this.findNodeById(startNode,commonTargetId); + } }); export{FindNodeMixin}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js index 0ee985e..ccbfcc3 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js @@ -29,6 +29,10 @@ var IdGen = Ember.Object.extend({ reset(){ this.nameCount=0; this.idCount=0; + }, + resetTo(val){ + this.nameCount=val; + this.idCount=val; } }); var idGen=IdGen.create({}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js new file mode 100644 index 0000000..c3e3133 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js @@ -0,0 +1,194 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import Ember from 'ember'; +import Constants from '../utils/constants'; +import {DefaultLayoutManager as LayoutManager} from '../domain/default-layout-manager'; +var JSPlumbRenderer= Ember.Object.extend({ + designerPlumb:null, + flattenedNodes:null, + _createConnection(sourceNode,target,transition){ + var connectionColor="#777"; + var lineWidth=1; + if (transition.condition){ + if(transition.condition==="default"){ + lineWidth=2; + }else if (transition.condition==="error"|| transition.errorPath){ + connectionColor=Constants.globalSetting.errorTransitionColor; + } + } + var connectionObj={ + source:sourceNode.id, + target:target.id, + connector:["Straight"], + paintStyle:{lineWidth:lineWidth,strokeStyle:connectionColor}, + endpointStyle:{fillStyle:'rgb(243,229,0)'}, + endpoint: ["Dot", { + radius: 1 + }], + alwaysRespectStubs:true, + anchors: [["Bottom"],["Top"]], + overlays:[] + }; + return connectionObj; + }, + _getAddNodeOverlay(context,sourceNode,target,transition){ + var location=target.type==="placeholder"?1:0.5; + var transitionCount=sourceNode.transitions.length; + return { + id: sourceNode.id+"_"+target.id+"_"+"connector", + location:location, + /* jshint unused:vars */ + create:function(component) { + var container=Ember.$('<div />'); + var plus= Ember.$('<div class="fa fa-plus connector_overlay_new"></div>'); + if ((sourceNode.isDecisionNode() && transitionCount>1 ||sourceNode.isForkNode() && transitionCount>2 ) && + target.isPlaceholder() && + !transition.isDefaultCasePath()){ + var trash=Ember.$('<div class="node_actions node_left"><i class="fa fa-trash-o"></i></div>'); + trash.on("click",function(){ + context.deleteTransition(transition); + }); + plus.append(trash); + } + container.append(plus); + return container; + }, + events:{ + click:function(labelOverlay, originalEvent) { + var element = originalEvent.target; + context.set('popOverElement', element); + context.setCurrentTransition(transition); + context.showWorkflowActionSelect(element); + } + } + }; + }, + + _renderNodes(node,visitedNodes){ + if (!node || node.isKillNode()){ + return; + } + if (visitedNodes.contains(node)){ + return; + } + visitedNodes.push(node); + if(!this.get("flattenedNodes").contains(node)){ + this.get("flattenedNodes").pushObject(node); + } + if (node.transitions.length > 0){ + node.transitions.forEach(function(transition) { + var target = transition.targetNode; + this._renderNodes(target,visitedNodes); + }.bind(this)); + } + }, + _connectNodes(context,sourceNode){ + var connections=[]; + var visitedNodes=[]; + this._renderTransitions(sourceNode,connections,visitedNodes,context); + this._layout(connections); + this.designerPlumb.setSuspendDrawing(true); + this.designerPlumb.batch(function(){ + connections.forEach(function(conn){ + this.designerPlumb.connect(conn); + }.bind(this)); + }.bind(this)); + this.designerPlumb.setSuspendDrawing(false,true); + + }, + _renderTransitions(sourceNode,connections,visitedNodes,context){ + var self=this; + if(!sourceNode){ + return; + } + if (visitedNodes.contains(sourceNode)){ + return; + } + if (sourceNode.hasTransition() ){ + sourceNode.transitions.forEach(function(transition) { + var target = transition.targetNode; + if (target.isKillNode() || !Constants.showErrorTransitions && transition.isOnError()){ + return; + } + var connectionObj=self._createConnection(sourceNode,target,transition); + + if (transition.condition){ + var conditionHTML = "<div class='decision-condition' title='"+transition.condition+"'>"+ transition.condition+"</div>"; + connectionObj.overlays.push([ "Label", {label:conditionHTML, location:0.75, id:"myLabel" } ]); + } + if (!target.isPlaceholder()){ + connectionObj.overlays.push(["PlainArrow",{location:-0.1,width: 7,length: 7}]); + } + if (!(sourceNode.isPlaceholder() || target.isKillNode())){ + var addNodeoverlay=["Custom" , self._getAddNodeOverlay(context,sourceNode,target,transition)]; + connectionObj.overlays.push(addNodeoverlay); + } + connections.push(connectionObj); + self._renderTransitions(target,connections,visitedNodes,context); + }); + } + }, + _layout(edges){ + var nodes = Ember.$(".nodecontainer"); + this.layoutManager.doLayout(this.get("context"),nodes,edges,this.get("workflow")); + }, + initRenderer(callback,settings){ + this.designerPlumb=jsPlumb.getInstance({}); + this.layoutManager=LayoutManager.create({}); + this.context=settings.context; + this.flattenedNodes=settings.flattenedNodes; + this.designerPlumb.ready(function() { + callback(); + }.bind(this)); + return this.designerPlumb; + }, + refresh(){ + this.designerPlumb.repaintEverything(); + }, + reset(){ + if(!this.get('flattenedNodes')){ + return; + } + this.get("flattenedNodes").clear(); + this.designerPlumb.reset(); + }, + cleanup(){ + if(!this.get('flattenedNodes')){ + return; + } + this.get('flattenedNodes').clear(); + this.designerPlumb.detachEveryConnection(); + }, + onDidUpdate(){ + this._connectNodes(this.get("context"),this.get("workflow").startNode,this.get("workflow")); + }, + renderWorkflow(workflow){ + var visitedNodes=[]; + this.set("workflow",workflow); + this._renderNodes(this.get("workflow").startNode,visitedNodes); + }, + + getBottomPosition(){ + return { + top : this.get("context").$(".nodeEnd").offset().top, + left : this.get("context").$(".nodeEnd").offset().left + }; + } + +}); +export {JSPlumbRenderer}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js index 7cb82e1..2962e71 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js @@ -22,7 +22,6 @@ var MappingMixin= Ember.Mixin.create({ handleMapping(nodeDomain,nodeObj,mappings,nodeName){ var self=this; mappings.forEach(function(mapping){ - var nodeVals=[]; if (mapping.mandatory){ if (!(nodeDomain[mapping.domain] || mapping.customHandler)){ var msgForVal=mapping.domain; @@ -113,6 +112,7 @@ var MappingMixin= Ember.Mixin.create({ } }); var ConfigurationMapper= Ember.Object.extend({ + /* jshint unused:vars */ hanldeGeneration(node,nodeObj){ if (!node || !node.configuration || !node.configuration.property){ return; @@ -205,24 +205,25 @@ var SLAMapper= Ember.Object.extend({ hanldeGeneration(sla,nodeObj){ if (sla){ var slaInfo=nodeObj["info"]={}; - slaInfo["__prefix"]="sla"; + var slaPrefix="sla"; + slaInfo["__prefix"]=slaPrefix; if (sla.nominalTime){ - slaInfo["nominal-time"]=sla.nominalTime; + slaInfo[slaPrefix+":"+"nominal-time"]=sla.nominalTime; } if (sla.shouldStart){ - slaInfo["should-start"]="${"+sla.shouldStart.time+ "*"+sla.shouldStart.unit+"}"; + slaInfo[slaPrefix+":"+"should-start"]="${"+sla.shouldStart.time+ "*"+sla.shouldStart.unit+"}"; } if (sla.shouldEnd){ - slaInfo["should-end"]="${"+sla.shouldEnd.time+ "*"+sla.shouldEnd.unit+"}"; + slaInfo[slaPrefix+":"+"should-end"]="${"+sla.shouldEnd.time+ "*"+sla.shouldEnd.unit+"}"; } if (sla.maxDuration){ - slaInfo["max-duration"]="${"+sla.maxDuration.time+ "*"+sla.maxDuration.unit+"}"; + slaInfo[slaPrefix+":"+"max-duration"]="${"+sla.maxDuration.time+ "*"+sla.maxDuration.unit+"}"; } if (sla.alertEvents){ - slaInfo["alert-events"]=sla.alertEvents; + slaInfo[slaPrefix+":"+"alert-events"]=sla.alertEvents; } if (sla.alertContact){ - slaInfo["alert-contact"]=sla.alertContact; + slaInfo[slaPrefix+":"+"alert-contact"]=sla.alertContact; } } @@ -230,18 +231,22 @@ var SLAMapper= Ember.Object.extend({ }, handleImport(domain,infoJson,key){ var sla=domain[key]=SlaInfo.create({}); - if (infoJson["nominal-time"]){ - sla.nominalTime=infoJson["nominal-time"]; + if (infoJson["nominal-time"] && infoJson["nominal-time"].__text){ + sla.nominalTime=infoJson["nominal-time"].__text; + } + if (infoJson["alert-contact"]&& infoJson["alert-contact"].__text){ + sla.alertContact=infoJson["alert-contact"].__text; + } + if (infoJson["alert-events"] && infoJson["alert-events"].__text){ + sla.alertEvents=infoJson["alert-events"].__text; } - sla.alertContact=infoJson["alert-contact"]; - sla.alertEvents=infoJson["alert-events"]; this.processTimePeriods(sla,infoJson,"should-start","shouldStart"); this.processTimePeriods(sla,infoJson,"should-end","shouldEnd"); this.processTimePeriods(sla,infoJson,"max-duration","maxDuration"); }, processTimePeriods(sla,infoJson,key,domainKey){ if (infoJson[key]){ - var timeParts=this.parseSlaTime(infoJson[key],key); + var timeParts=this.parseSlaTime(infoJson[key].__text,key); sla[domainKey].time=timeParts[0]; sla[domainKey].unit=timeParts[1]; } http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js index c440b8c..b6e2c73 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js @@ -21,10 +21,10 @@ import {Node} from '../domain/node'; import {idGen} from '../domain/id-gen'; var NodeFactory= Ember.Object.extend({ createStartNode(){ - return this.createNode({id:'node-start', type:'start',name:"Start"}); + return this.createNode({id:this.generateNodeId(), type:'start',name:"Start"}); }, createEndNode(name){ - return this.createNode({id:'node-end', type:'end', name:name}); + return this.createNode({id:this.generateNodeId(), type:'end', name:name}); }, createKillNode(name,message){ return this.createNode({id:this.generateNodeId(), type:"kill", name:name,killMessage:message}); @@ -108,6 +108,9 @@ var NodeFactory= Ember.Object.extend({ }, createNode(settings){ settings.factory=this; + if (!settings.id){ + settings.id=this.generateNodeId(); + } return Node.create(settings); }, generateNodeId(){ @@ -115,6 +118,9 @@ var NodeFactory= Ember.Object.extend({ }, generateName(){ return idGen.generateNodeName(); + }, + resetNodeIdTo(id){ + return idGen.resetTo(id); } }); export{NodeFactory}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js index 49347d8..6bc305a 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js @@ -17,49 +17,8 @@ import Ember from 'ember'; import {NodeFactory} from '../domain/node-factory'; -import * as actionJobHandler from '../domain/actionjob_hanlder'; -import {SlaInfo} from '../domain/sla-info'; import {SLAMapper} from "../domain/mapping-utils"; -var ActionTypeResolver=Ember.Object.extend({ - actionJobHandlerMap:null, - validStandardActionProps:["ok","error","info"], - init(){ - var settings={schemaVersions:this.schemaVersions}; - this.actionJobHandlerMap=new Map(); - this.actionJobHandlerMap.set("java",actionJobHandler.JavaActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("pig",actionJobHandler.PigActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("hive",actionJobHandler.HiveActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("hive2",actionJobHandler.Hive2ActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("sqoop",actionJobHandler.SqoopActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("shell",actionJobHandler.ShellActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("spark",actionJobHandler.SparkActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("map-reduce",actionJobHandler.MapRedActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("sub-workflow",actionJobHandler.SubWFActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("distcp",actionJobHandler.DistCpJobHandler.create(settings)); - this.actionJobHandlerMap.set("ssh",actionJobHandler.SshActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("email",actionJobHandler.EmailActionJobHandler.create(settings)); - this.actionJobHandlerMap.set("fs",actionJobHandler.FSActionJobHandler.create(settings)); - }, - getActionType(json){ - var self=this; - var resolvedType=null; - var problaleActionsTypes=[]; - Object.keys(json).forEach(function functionName(key) { - if (!self.validStandardActionProps.contains(key) && !key.startsWith("_")){ - problaleActionsTypes.push(key); - } - }); - if (problaleActionsTypes.length===1){ - return problaleActionsTypes[0]; - }else{ - console.error("Invalid Action spec..",json); - } - return resolvedType; - }, - getActionJobHandler(jobType){ - return this.actionJobHandlerMap.get(jobType); - } -}); + var NodeHandler=Ember.Object.extend({ nodeFactory:NodeFactory.create({}), context : {}, @@ -75,12 +34,14 @@ var NodeHandler=Ember.Object.extend({ handleNode(node){ return {"_name":node.get("name")}; }, - + /* jshint unused:vars */ handleTransitions(transitions,nodeObj){ }, + /* jshint unused:vars */ handleImportNode(type,node){ }, + /* jshint unused:vars */ handleImportTransitions(node,json,nodeMap){ } }); @@ -248,4 +209,4 @@ var JoinNodeHandler= NodeHandler.extend({ node.addTransitionTo(nodeMap.get(json._to).node); } }); -export{ActionTypeResolver,NodeHandler,StartNodeHandler,EndNodeHandler,KillNodeHandler,ActionNodeHandler,DecisionNodeHandler,ForkNodeHandler,JoinNodeHandler}; +export{NodeHandler,StartNodeHandler,EndNodeHandler,KillNodeHandler,ActionNodeHandler,DecisionNodeHandler,ForkNodeHandler,JoinNodeHandler}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js index c7ce003..cda7609 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js @@ -100,7 +100,7 @@ var Node = Ember.Object.extend(FindNodeMixin,{ } }, addTransitionTo(target,condition){ - var transition = Transition.create({targetNode:target,sourceNode:this,condition:condition}); + var transition = Transition.create({targetNode:target,sourceNodeId:this.id,condition:condition}); this.addTransition(transition); return transition; }, @@ -120,7 +120,6 @@ var Node = Ember.Object.extend(FindNodeMixin,{ }, removeTransition(transition){ - var transitions=this.get("transitions"); if (transition && this.transitions.indexOf(transition) > -1) { this.transitions.splice(this.transitions.indexOf(transition), 1); } http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js index 76dffbd..9d90280 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js @@ -17,43 +17,43 @@ import Ember from 'ember'; var SlaInfo = Ember.Object.extend(Ember.Copyable,{ copy (){ - var slaInfo = {} + var slaInfo = {}; for (let key in this) { slaInfo[key] = Ember.copy(this[key]) ; } return slaInfo; }, init (){ - this.nominalTime=''; + this.nominalTime=undefined; this.shouldStart = { - time : '', - unit : '' + time : undefined, + unit : undefined }; this.shouldEnd = { - time : '', - unit : '' + time : undefined, + unit : undefined }; this.maxDuration = { - time : '', - unit : '' + time : undefined, + unit : undefined }; - this.alertEvents = ''; - this.alertContacts = ''; + this.alertEvents = undefined; + this.alertContacts = undefined; }, - nominalTime:'', + nominalTime:undefined, shouldStart : { - time : '', - unit : '' + time : undefined, + unit : undefined }, shouldEnd : { - time : '', - unit : '' + time : undefined, + unit : undefined }, maxDuration : { - time : '', - unit : '' + time : undefined, + unit : undefined }, - alertEvents : '', - alertContacts : '' + alertEvents : undefined, + alertContacts : undefined }); export {SlaInfo}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js index 70d7a81..b14484e 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js @@ -18,7 +18,6 @@ import Ember from 'ember'; var Transition = Ember.Object.extend({ id:null, - sourceNode:null, targetNode:null, type:null, condition:null, @@ -35,9 +34,7 @@ var Transition = Ember.Object.extend({ isDefaultCasePath(){ return this.condition==="default"; }, - getSourceNode(){ - return this.get("sourceNode"); - }, + getTargetNode(skipPlaceholder){ var currNode=this.targetNode; if (skipPlaceholder===false){ http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js index f29adb6..7415544 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js @@ -95,7 +95,7 @@ var WorkflowImporter= Ember.Object.extend({ }, getNodeIds(nodeMap){ var ids=[]; - nodeMap.forEach(function(entry,key){ + nodeMap.forEach(function(entry){ var node=entry.node; ids.push(node.id); }); @@ -103,7 +103,7 @@ var WorkflowImporter= Ember.Object.extend({ }, getNodeNames(nodeMap){ var names=[]; - nodeMap.forEach(function(entry,key){ + nodeMap.forEach(function(entry){ var node=entry.node; names.push(node.id); }); @@ -113,7 +113,7 @@ var WorkflowImporter= Ember.Object.extend({ if (this.containsKillNode(nodeMap)){ workflow.resetKillNodes(); } - nodeMap.forEach(function(entry,key){ + nodeMap.forEach(function(entry){ var node=entry.node; if (node.isKillNode()){ workflow.get("killNodes").pushObject(node); @@ -122,7 +122,7 @@ var WorkflowImporter= Ember.Object.extend({ }, containsKillNode(nodeMap){ var containsKillNode=false; - nodeMap.forEach(function(entry,key){ + nodeMap.forEach(function(entry){ var node=entry.node; if (node.isKillNode()){ containsKillNode=true; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js new file mode 100644 index 0000000..fa428bb --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import Ember from 'ember'; +import {Workflow} from '../domain/workflow'; +import {NodeFactory} from '../domain/node-factory'; +var WorkflowJsonImporter= Ember.Object.extend({ + nodeFactory:NodeFactory.create({}), + importWorkflow(workflowJsonStr){ + if (!workflowJsonStr){ + return null; + } + try{ + var workflowJson=JSON.parse(workflowJsonStr); + var workflow=Workflow.create({}); + workflow.initialize(); + workflow.set("name",workflowJson.name); + this.restoreKillNodes(workflowJson.killNodes,workflow); + var nodeMap= new Map(); + var startNode=this.visitNode(workflowJson.startNode,nodeMap); + workflow.set("startNode",startNode); + var maxId=0; + for(let value of nodeMap.keys()){ + console.log("Value in it=",value); + var id=Number.parseInt(value.substr(5)); + if (id>maxId){ + maxId=id; + } + } + this.nodeFactory.resetNodeIdTo(maxId+1); + console.log("imported workflow==",workflow); + return workflow; + }catch(e){ + console.error(e); + return null; + } + }, + visitNode(nodeJson,nodeMap){ + var self=this; + if (!nodeJson){ + return; + } + var node; + if (!nodeMap.has(nodeJson.id)){ + node=this.nodeFactory.createNode({id:nodeJson.id, type:nodeJson.type,name:nodeJson.name,actionType:nodeJson.actionType,killMessage:nodeJson.killMessage}); + node.set("domain",nodeJson.domain); + node.set("errorMsgs",nodeJson.errorMsgs); + node.set("errors",nodeJson.errors); + nodeMap.set(node.id,node); + if (nodeJson.transitions){ + nodeJson.transitions.forEach(function(nodeTran){ + var transitions=nodeTran; + if (!Ember.isArray(nodeTran)){ + transitions=[nodeTran]; + } + transitions.forEach(function(tran){ + var targetNodeJson=tran.targetNode; + var targetNode=self.visitNode(targetNodeJson,nodeMap); + node.addTransitionTo(targetNode,tran.condition); + }); + }); + } + }else{ + node=nodeMap.get(nodeJson.id); + } + return node; + }, + restoreKillNodes(killnodesJson,workflow){ + if (!killnodesJson){ + return; + } + workflow.resetKillNodes(); + killnodesJson.forEach(function(killNodeJson){ + workflow.createKillNode(killNodeJson.name,killNodeJson.killMessage); + }); + console.log("killnodes json=",killnodesJson); + } +}); +export {WorkflowJsonImporter}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js new file mode 100644 index 0000000..c921455 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js @@ -0,0 +1,73 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import Ember from 'ember'; +export default Ember.Object.create({ + findPath(source, target){ + var visitedNodes = []; + var currentPath = []; + var allPaths = []; + this._findPath(source, target, visitedNodes, currentPath, 0, allPaths); + return allPaths; + }, + _findPath(source, target, visitedNodes, currentPath, pathIndex, allPaths){ + visitedNodes.pushObject(source); + currentPath[pathIndex++] = source; + if(source.id === target.id){ + if(!allPaths[allPaths.length]){ + var index = currentPath.indexOf(target); + allPaths[allPaths.length] = currentPath.slice(0, index+1); + } + } + if(source.hasTransition()){ + source.transitions.forEach((transition)=>{ + var node = transition.targetNode; + if(node.hasTransition() && !visitedNodes.findBy('id', node.id)){ + this._findPath(node, target, visitedNodes, currentPath, pathIndex, allPaths); + } + }, this); + } + pathIndex--; + visitedNodes.removeObject(source); + }, + _getAllNodes(workflow){ + var workflowNodes = []; + workflow.nodeVisitor.process(workflow.startNode, (node) =>{ + workflowNodes.pushObject(node); + }); + return workflowNodes; + }, + findValidTransitionsTo(workflow, node){ + var validTransitionsTo = []; + if(!node.hasTransition()){ + return validTransitionsTo; + } + var paths = this.findPath(workflow.get('startNode'), node); + var workflowNodes = this._getAllNodes(workflow); + validTransitionsTo = workflowNodes.slice(); + workflowNodes.forEach((node)=>{ + paths.forEach((path)=>{ + if(path.contains(node)){ + validTransitionsTo.removeObject(node); + } + }, this); + }, this); + validTransitionsTo = validTransitionsTo.reject((node)=>{ + return node.get('type') === 'placeholder'; + }, this); + return validTransitionsTo; + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js index 9fc791c..7049fde 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js @@ -18,7 +18,6 @@ import Ember from 'ember'; import {WorkflowXmlMapper} from '../domain/workflow_xml_mapper'; import {NodeVisitor} from '../domain/node-visitor'; -import Constants from '../utils/constants'; var WorkflowGenerator= Ember.Object.extend({ workflowMapper:null, x2js : new X2JS({useDoubleQuotes:true}), http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js index 5908de5..f4fc20d 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js @@ -21,8 +21,7 @@ import {FindNodeMixin} from '../domain/findnode-mixin'; import {NodeFactory} from '../domain/node-factory'; import SchemaVersions from '../domain/schema-versions'; import {NodeVisitor} from '../domain/node-visitor'; -import {idGen} from '../domain/id-gen'; -import {SlaInfo} from '../domain/sla-info' +import {SlaInfo} from '../domain/sla-info'; var Workflow= Ember.Object.extend(FindNodeMixin,{ name:"", startNode:null, @@ -60,52 +59,13 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ //TODO idGen.reset(); this.initialize(); }, - findCommonTargetNodeId(node){ - var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0; - for(var i =0; i< decPath.length; i++){ - var currNode = decPath[i]; - do { - if(nodeIds.hasOwnProperty(currNode.get("id"))){ - nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1; - } else { - nodeIds[currNode.get("id")] = 1; - } - if(currNode.get("id") === "node-end"){ - break; - } - currNode = currNode.getTargets()[0]; - } while(currNode && currNode.get("id")); - } - for(var j in nodeIds){ - if(tempId < nodeIds[j]){ - targ = j; - tempId = nodeIds[j]; - } - } - return targ; - }, + findJoinNode(node){ - var commonTargetId=null; - var commonTarget=null; - if (node.isDecisionNode()){ - if (Constants.globalSetting.useJoinNodeForDecision){ - var target=this.findNodeById(node,"decision_end_"+node.get("id")); - if (!target){ - commonTargetId=this.findCommonTargetNodeId(node); - commonTarget=this.findNodeById(this.startNode,commonTargetId); - return commonTarget; - }else{ - return target; - } - }else{ - commonTargetId=this.findCommonTargetNodeId(node); - commonTarget=this.findNodeById(this.startNode,commonTargetId); - return commonTarget; - } + if (node.isDecisionNode() || node.isForkNode()){ + return this.findCommonTargetNode(this.startNode,node); }else if (node.isForkNode()) { - commonTargetId=this.findCommonTargetNodeId(node); - commonTarget=this.findNodeById(this.startNode,commonTargetId); - return commonTarget; + //TODO find join node by id if it is efficient later.. + return this.findCommonTargetNode(this.startNode,node); }else{ return null; } @@ -136,7 +96,7 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ }else{ } }, - generatedNode(target,type){ + generatedNode(target,type,settings){ var generatedNode=null; if ("decision" === type){ generatedNode=this.nodeFactory.generateDecisionNode(target); @@ -144,32 +104,38 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ generatedNode=this.nodeFactory.generateForkNode(target); }else if ("kill" === type){ generatedNode = this.nodeFactory.createKillNode(settings.name); - source.deleteCurrentKillNode(); + //source.deleteCurrentKillNode();//TODO how to get source... }else{ generatedNode = this.nodeFactory.createActionNode(type); generatedNode.addTransitionTo(target); } return generatedNode; }, - addKillNode(node,settings){ - var generatedNode=this.generatedNode(null,"kill"); + + addKillNode(source,settings){ + var generatedNode=this.generatedNode(null,"kill",settings); return source.addTransitionTo(generatedNode,"error"); }, addNode(transition,type,settings) { - var source=transition.sourceNode; var target=transition.targetNode; var computedTarget=target; if (target && target.isPlaceholder()){ computedTarget=target.getTargets()[0]; } - var generatedNode=this.generatedNode(computedTarget,type); - transition.targetNode=generatedNode; + var generatedNode=this.generatedNode(computedTarget,type,settings); + var sourceNode=this.findNodeById(this.startNode,transition.sourceNodeId); + if (sourceNode.isPlaceholder()){ + var orignalTransition=this.findTransitionTo(this.startNode,sourceNode.id); + orignalTransition.targetNode=generatedNode; + }else{ + transition.targetNode=generatedNode; + } return generatedNode; }, deleteKillNode(node){ let killNodes = this.get("killNodes"); var killNodeReferenced=false; - this.nodeVisitor.process(this.startNode,function(n,ctx){ + this.nodeVisitor.process(this.startNode,function(n){ if (n.errorNode && n.errorNode.name===node.name){ killNodeReferenced=true; } @@ -195,35 +161,37 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ var target=node.getDefaultTransitionTarget(); if (node.isForkNode()|| node.isDecisionNode()){ target=this.findJoinNode(node); + if (!target){//A bug will give target as null if the decision has single path. + target=node.getDefaultTransitionTarget(); + } if (target.isJoinNode()){ target=target.getDefaultTransitionTarget(); } } var transitionslist=this.findTransistionsToNode(node); transitionslist.forEach(function(tran){ - if (tran.getSourceNode().isDecisionNode()){ - var joinNode=self.findJoinNode(tran.getSourceNode()); + var sourceNode=self.findNodeById(self.startNode,tran.sourceNodeId); + var joinNode; + if (sourceNode.isDecisionNode()){ + joinNode=self.findJoinNode(sourceNode); if (joinNode===target){ if (tran.isDefaultCasePath()){ - var placeholderNode=self.nodeFactory.createPlaceholderNode(target); - tran.targetNode=placeholderNode; - }else if (tran.getSourceNode().getOkTransitionCount()>2){ - tran.getSourceNode().removeTransition(tran); + tran.targetNode=self.nodeFactory.createPlaceholderNode(target); + }else if (sourceNode.getOkTransitionCount()>2){ + sourceNode.removeTransition(tran); }else{ - var placeholderNode=self.nodeFactory.createPlaceholderNode(target); - tran.targetNode=placeholderNode; + tran.targetNode=self.nodeFactory.createPlaceholderNode(target); } }else{ tran.targetNode=target; } - }else if (tran.getSourceNode().isForkNode()){ - var joinNode=self.findJoinNode(tran.getSourceNode()); + }else if (sourceNode.isForkNode()){ + joinNode=self.findJoinNode(sourceNode); if (joinNode===target){ - if (tran.getSourceNode().getOkTransitionCount()>2){ - tran.getSourceNode().removeTransition(tran); + if (sourceNode.getOkTransitionCount()>2){ + sourceNode.removeTransition(tran); }else{ - var placeholderNode=self.nodeFactory.createPlaceholderNode(target); - tran.targetNode=placeholderNode; + tran.targetNode=self.nodeFactory.createPlaceholderNode(target); } }else{ tran.targetNode=target; @@ -234,13 +202,15 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ }); }, deleteTransition(transition){ - var src=transition.getSourceNode(); + var src=this.findNodeById(this.startNode,transition.sourceNodeId); src.removeTransition(transition); }, deleteEmptyTransitions(transitionslist){ + var self=this; transitionslist.forEach(function(tran){ - if (tran.getSourceNode().isForkNode()&& tran.getTargetNode().isJoinNode()){ - tran.getSourceNode().removeTransition(tran); + var sourceNode=this.findNodeById(self.startNode,tran.sourceNodeId); + if (sourceNode.isForkNode()&& tran.getTargetNode().isJoinNode()){ + sourceNode.removeTransition(tran); } }); }, @@ -261,6 +231,4 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{ } } }); - - export {Workflow}; http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js index d5dc4da..70581bf 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js @@ -18,6 +18,7 @@ import Ember from 'ember'; import * as nodeHandler from '../domain/node-handler'; import {SLAMapper} from "../domain/mapping-utils"; +import {ActionTypeResolver} from "../domain/action-type-resolver"; import {MappingMixin,ConfigurationMapper} from "../domain/mapping-utils"; var WorkflowXmlMapper= Ember.Object.extend({ @@ -27,7 +28,7 @@ var WorkflowXmlMapper= Ember.Object.extend({ slaMapper: SLAMapper.create({}), schemaVersions:null, init: function() { - this.actionTypeResolver=nodeHandler.ActionTypeResolver.create({schemaVersions:this.schemaVersions}); + this.actionTypeResolver=ActionTypeResolver.create({schemaVersions:this.schemaVersions}); this.set("globalConfigHandler",GlobalConfigHandler.create({})); this.set("slaMapper",SLAMapper.create({})); this.nodeHandlerMap=new Map(); @@ -106,7 +107,7 @@ var WorkflowXmlMapper= Ember.Object.extend({ if (!parameters|| !parameters.property){ return; } - workflow.parameters={"configuration":{property:[]}} + workflow.parameters={"configuration":{property:[]}}; parameters.property.forEach(function(prop){ workflow.parameters.configuration.property.push({"name":prop.name,"value":prop.value}); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/index.html ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/index.html b/contrib/views/wfmanager/src/main/resources/ui/app/index.html index a317a48..df243ad 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/index.html +++ b/contrib/views/wfmanager/src/main/resources/ui/app/index.html @@ -33,6 +33,15 @@ </head> <body> + +<div style="display:none;"> +<!-- preloading images for designer--> + <img src="assets/play.png"/> + <img src="assets/stop.png"/> + <img src="assets/join.png"/> + <img src="assets/sitemap.png"/> +</div> + {{content-for "body"}} <script src="assets/vendor.js"></script> <script src="assets/oozie-designer.js"></script> http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js index d0ef5e0..949d39a 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js @@ -62,11 +62,19 @@ export default Ember.Route.extend({ }); return deferred.promise; }, + setPageResultLen(){ + /* + setting the no of jobs to be displayed to multiple of 5 + */ + var relHeight = parseInt(Ember.$(window).width()/100); + return relHeight - relHeight%5; + }, search(params){ params = params || {}; var type = params.type || "wf", start = Number(params.start || 1), - len = Number(params.len || Ember.ENV.PAGE_SIZE), + //len = Number(params.len || Ember.ENV.PAGE_SIZE), + len = this.setPageResultLen(), index = 0, filter = params.filter || "", API_URL = Ember.ENV.API_URL, http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js index cec0e9e..5ed2619 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js @@ -1,25 +1,27 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ import Ember from 'ember'; export default Ember.Route.extend({ -xmlAppPath : null, -beforeModel: function(transition){ - this.set("xmlAppPath", transition.queryParams.appPath); + + beforeModel: function(transition){ + this.set("xmlAppPath", transition.queryParams.appPath); + this.controllerFor('design').set("xmlAppPath", transition.queryParams.appPath); } + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js new file mode 100644 index 0000000..8784cda --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js @@ -0,0 +1,34 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import Ember from 'ember'; + +export default Ember.Service.extend({ + clipboard : null, + setContent(node, operation){ + var clipboardContent = { + name : node.name, + domain : Ember.copy(node.domain), + type : node.type, + actionType : node.actionType, + operation : operation + }; + this.set('clipboard', clipboardContent); + }, + getContent (){ + return this.get('clipboard'); + } +});
