You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/10/28 17:45:48 UTC
[09/38] ambari git commit: AMBARI-18691. Improve and Update Workflow
designer to support coordinators and bundles. (Belliraj HB via dipayanb)
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');
+ }
+});