You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2016/08/09 20:15:01 UTC

[08/12] ambari git commit: AMBARI-17213. Create ambari workflow designer contrib view. (Venkat Ranganathan via yusaku)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..f29adb6
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
@@ -0,0 +1,134 @@
+/*
+*    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 CommonUtils from "../utils/common-utils";
+import {Workflow} from '../domain/workflow';
+import {WorkflowXmlMapper} from '../domain/workflow_xml_mapper';
+var WorkflowImporter= Ember.Object.extend({
+  workflowMapper:null,
+  x2js : new X2JS(),
+  importWorkflow(workflowXml){
+    var workflow=Workflow.create({});
+    workflow.initialize();
+    this.workflowMapper=WorkflowXmlMapper.create({schemaVersions:workflow.schemaVersions});
+    return this.processWorkflowXml(workflowXml,workflow);
+  },
+  processWorkflowXml(workflowXml,workflow){
+    var workflowJson= this.get("x2js").xml_str2json(workflowXml);
+    if (!workflowJson["workflow-app"]){
+      throw "Invalid workflow";
+    }
+    var workflowAppJson=workflowJson["workflow-app"];
+    var workflowVersion=CommonUtils.extractSchemaVersion(workflowAppJson._xmlns);
+    workflow.schemaVersions.setCurrentWorkflowVersion(workflowVersion);
+    if (workflowAppJson.info && workflowAppJson.info.__prefix==="sla") {
+      workflow.slaEnabled=true;
+      this.workflowMapper.handleSLAImport(workflow,workflowAppJson.info);
+    }
+    this.workflowMapper.handleCredentialImport(workflow,workflowAppJson.credentials);
+    this.workflowMapper.handleParametersImport(workflow,workflowAppJson.parameters);
+    var nodeMap=this.setupNodeMap(workflowAppJson,workflow);
+    this.setupTransitions(workflowAppJson,nodeMap);
+    workflow.set("startNode",nodeMap.get("start").node);
+    this.populateKillNodes(workflow,nodeMap);
+    return workflow;
+  },
+  processActionNode(nodeMap,action){
+    var actionMapper=this.get("workflowMapper").getNodeHandler("action");
+    var actionNode=actionMapper.handleImportNode(action);
+    nodeMap.set(actionNode.getName(),actionNode);
+  },
+  setupNodeMap(workflowAppJson,workflow){
+    var self=this;
+    workflow.set("name",workflowAppJson["_name"]);
+    var nodeMap=new Map();
+    Object.keys(workflowAppJson).forEach(function (key) {
+      var nodeHandler=self.workflowMapper.getNodeHandler(key);
+      if (nodeHandler){
+        if (Ember.isArray(workflowAppJson[key])){
+          workflowAppJson[key].forEach(function(jsonObj){
+            var node=nodeHandler.handleImportNode(key,jsonObj,workflow);
+            nodeMap.set(jsonObj._name,{json:jsonObj,node:node});
+          });
+        }else{
+          var node=nodeHandler.handleImportNode(key,workflowAppJson[key],workflow);
+          if (!workflowAppJson[key]._name){
+            nodeMap.set(key,{json:workflowAppJson[key],node:node});
+          }else{
+            nodeMap.set(workflowAppJson[key]._name,{json:workflowAppJson[key],node:node});
+          }
+        }
+      }
+    });
+    return nodeMap;
+  },
+  setupTransitions(workflowAppJson,nodeMap){
+    var self=this;
+    nodeMap.forEach(function(entry,key){
+      var node=entry.node;
+      if (!node){
+        console.error("could not process:",key);//TODO error handling...
+        return;
+      }
+      var json=entry.json;
+      var nodeHandler=self.workflowMapper.getNodeHandler(node.get("type"));
+      if (!nodeHandler){
+        console.error("could not process:",node.get("type"));//TODO error handling...
+      }
+      nodeHandler.handleImportTransitions(node,json,nodeMap);
+    });
+  },
+  getNodeIds(nodeMap){
+    var ids=[];
+    nodeMap.forEach(function(entry,key){
+      var node=entry.node;
+      ids.push(node.id);
+    });
+    return ids;
+  },
+  getNodeNames(nodeMap){
+    var names=[];
+    nodeMap.forEach(function(entry,key){
+      var node=entry.node;
+      names.push(node.id);
+    });
+    return names;
+  },
+  populateKillNodes(workflow,nodeMap){
+    if (this.containsKillNode(nodeMap)){
+      workflow.resetKillNodes();
+    }
+    nodeMap.forEach(function(entry,key){
+      var node=entry.node;
+      if (node.isKillNode()){
+        workflow.get("killNodes").pushObject(node);
+      }
+    });
+  },
+  containsKillNode(nodeMap){
+    var containsKillNode=false;
+    nodeMap.forEach(function(entry,key){
+      var node=entry.node;
+      if (node.isKillNode()){
+        containsKillNode=true;
+      }
+    });
+    return containsKillNode;
+  }
+});
+export {WorkflowImporter};

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..9fc791c
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
@@ -0,0 +1,144 @@
+/*
+ *    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 {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}),
+  workflow:null,
+  workflowContext : {},
+  nodeVisitor:null,
+  ignoreErrors:false,
+  init(){
+    this.workflowMapper=WorkflowXmlMapper.create({schemaVersions:this.workflow.schemaVersions});
+    this.nodeVisitor=NodeVisitor.create({});
+  },
+  process(){
+    if (!this.ignoreErrors && (!this.workflow.get("name") || this.workflow.get("name").trim()==="")){
+      this.workflowContext.addError({message : "Workflow name is mandatory"});
+      return;
+    }
+    var workflowObj={"workflow-app":{}};
+    this.get("workflowMapper").getGlobalConfigHandler().handle(this.workflow.get("globalSetting"),workflowObj["workflow-app"]);
+    this.visitNode(workflowObj,this.workflow.startNode);
+    if (this.workflow.slaEnabled===true){
+      this.get("workflowMapper").handleSLAMapping(this.workflow.sla,workflowObj["workflow-app"]);
+    }
+    this.get("workflowMapper").handleCredentialsGeneration(this.workflow.credentials,workflowObj["workflow-app"]);
+    this.get("workflowMapper").hanldeParametersGeneration(this.workflow.parameters,workflowObj["workflow-app"]);
+    if (!this.ignoreErrors && (!workflowObj["workflow-app"].action || workflowObj["workflow-app"].action.length<1)){
+      this.workflowContext.addError({message : "Miniumum of one action node must exist"});
+      return;
+    }
+    var reordered={"workflow-app":{}};
+    var srcWorkflowApp=workflowObj["workflow-app"];
+    var targetWorkflowApp=reordered["workflow-app"];
+    targetWorkflowApp["_name"]=this.workflow.get("name");
+    this.copyProp(srcWorkflowApp,targetWorkflowApp,["parameters","global","credentials","start","decision","fork","join","action","kill","end","info"]);
+    targetWorkflowApp["_xmlns"]="uri:oozie:workflow:"+this.workflow.get("schemaVersions").getCurrentWorkflowVersion();
+    if (this.slaInfoExists(targetWorkflowApp)){
+      targetWorkflowApp["_xmlns:sla"]="uri:oozie:sla:0.2";
+    }
+    var xmlAsStr = this.get("x2js").json2xml_str(reordered);
+    return xmlAsStr;
+  },
+  slaInfoExists(workflowApp){
+    if (workflowApp.info){
+      return true;
+    }
+    var slaExists= false;
+    if (!workflowApp.action){
+      return false;
+    }
+    workflowApp.action.forEach(function(action){
+      if (action.info){
+        slaExists=true;
+      }
+    });
+    return slaExists;
+  },
+  copyProp(src,dest,props){
+    props.forEach(function(prop){
+      if (src[prop]){
+        dest[prop]=src[prop];
+      }
+    });
+  },
+
+  visitNode(workflowObj,node,visitedNodes){
+    if (!visitedNodes){
+      visitedNodes=[];
+    }
+    if (visitedNodes.contains(node.get("id"))){
+      return;
+    }
+    visitedNodes.push(node.get("id"));
+    var self=this;
+    var workflowApp=workflowObj["workflow-app"];
+    if (node.isPlaceholder()){
+      return self.visitNode(workflowObj,node.transitions[0].targetNode,visitedNodes);
+    }
+    var nodeHandler=this.get("workflowMapper").getNodeHandler(node.type);
+    nodeHandler.setContext(this.workflowContext);
+    var nodeObj=nodeHandler.handleNode(node);
+    if (node.type==='action'){
+      var jobHandler=this.get("workflowMapper").getActionJobHandler(node.actionType);
+      if (jobHandler){
+
+        jobHandler.setContext(this.workflowContext);
+        if (!self.ignoreErrors && !node.get("domain")){
+            this.workflowContext.addError({node : node, message : "Action Properties are empty"});
+        }else{
+          jobHandler.handle(node.get("domain"),nodeObj,node.get("name"));
+          if (!self.ignoreErrors){
+            var errors=jobHandler.validate(node.get("domain"));
+            if (errors && errors.length>0){
+              errors.forEach(function(err){
+                this.workflowContext.addError({node : node, message : err.message});
+              }.bind(this));
+            }
+          }
+        }
+      }else{
+        if (!self.ignoreErrors){
+          this.workflowContext.addError({node : node, message : "Unknown action:"+node.actionType});
+        }
+      }
+    }
+    if (nodeHandler.hasMany()){
+        if (!workflowApp[node.type]){
+            workflowApp[node.type]=[];
+        }
+      workflowApp[node.type].push(nodeObj);
+    }else{
+      workflowApp[node.type]=nodeObj;
+    }
+    nodeHandler.handleTransitions(node.transitions,nodeObj);
+    if (node.transitions){
+      node.transitions.forEach(function(tran){
+        self.visitNode(workflowObj,tran.targetNode,visitedNodes);
+      });
+    }
+    if (node.isActionNode()){
+      nodeHandler.handleSla(node.domain,nodeObj);
+    }
+  }
+});
+export {WorkflowGenerator};

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..5908de5
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
@@ -0,0 +1,266 @@
+/*
+*    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 {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'
+var Workflow= Ember.Object.extend(FindNodeMixin,{
+  name:"",
+  startNode:null,
+  globalSetting:null,
+  parameters: null,
+  usePlaceholders: true,
+  killNodes : null,
+  nodeVisitor : null,
+  nodeFactory:NodeFactory.create({}),
+  schemaVersions:SchemaVersions.create({}),
+  sla : SlaInfo.create({}),
+  credentials : Ember.A([]),
+  initialize(){
+    this.nodeVisitor=NodeVisitor.create({});
+    var src =this.nodeFactory.createStartNode();
+    var dest =this.nodeFactory.createEndNode("end");
+    this.set("startNode", src);
+    this.set("killNodes",Ember.A([]));
+    this.set("globalSetting",null);
+    this.set("name","");
+    this.appendDefaultKillNode();
+    src.addTransitionTo(dest);
+  },
+  appendDefaultKillNode(){
+    this.createKillNode(Constants.defaultKillNodeName,"${wf:errorMessage(wf:lastErrorNode())}");
+  },
+  createKillNode(name, message){
+    var killNode=this.nodeFactory.createKillNode(name,message);
+    this.get("killNodes").pushObject(killNode);
+  },
+  resetKillNodes(){
+    this.set("killNodes",Ember.A([]));
+  },
+  resetWorfklow(){
+    //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;
+      }
+    }else if (node.isForkNode()) {
+      commonTargetId=this.findCommonTargetNodeId(node);
+      commonTarget=this.findNodeById(this.startNode,commonTargetId);
+      return commonTarget;
+    }else{
+      return null;
+    }
+  },
+  addBranch(sourceNode){
+    var target=this.findJoinNode(sourceNode);
+    if (this.get("usePlaceholders")){
+      var placeholderNode=this.nodeFactory.createPlaceholderNode(target) ;
+      sourceNode.addTransitionTo(placeholderNode);
+    }else{
+      sourceNode.addTransitionTo(target);
+    }
+  },
+  addDecisionBranch(settings){
+    if (!settings.targetNode){
+      return;
+    }
+    var sourceNode=settings.sourceNode;
+    var insertNodeOnPath=settings.newNodeType?true:false;
+    var target=settings.targetNode;
+    if (!insertNodeOnPath){
+      if (this.get("usePlaceholders")){
+        var placeholderNode=this.nodeFactory.createPlaceholderNode(target) ;
+        sourceNode.addTransitionTo(placeholderNode,settings.condition);
+      }else{
+        sourceNode.addTransitionTo(target,settings.condition);
+      }
+    }else{
+    }
+  },
+  generatedNode(target,type){
+    var generatedNode=null;
+    if ("decision" === type){
+      generatedNode=this.nodeFactory.generateDecisionNode(target);
+    }else  if ("fork" === type){
+      generatedNode=this.nodeFactory.generateForkNode(target);
+    }else  if ("kill" === type){
+      generatedNode = this.nodeFactory.createKillNode(settings.name);
+      source.deleteCurrentKillNode();
+    }else{
+      generatedNode = this.nodeFactory.createActionNode(type);
+      generatedNode.addTransitionTo(target);
+    }
+    return generatedNode;
+  },
+  addKillNode(node,settings){
+    var generatedNode=this.generatedNode(null,"kill");
+    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;
+    return generatedNode;
+  },
+  deleteKillNode(node){
+    let killNodes = this.get("killNodes");
+    var killNodeReferenced=false;
+    this.nodeVisitor.process(this.startNode,function(n,ctx){
+      if (n.errorNode && n.errorNode.name===node.name){
+        killNodeReferenced=true;
+      }
+    });
+    if (killNodeReferenced){
+      return{
+        status: false,
+        message: "Kill node is being referenced by other nodes."
+      };
+    }
+    for(var i=0; i<killNodes.length; i++){
+      if(node.id === killNodes[i].id){
+        this.get("killNodes").removeObject(killNodes[i]);
+        break;
+      }
+    }
+    return {
+      status:true
+    };
+  },
+  deleteNode(node){
+    var self=this;
+    var target=node.getDefaultTransitionTarget();
+    if (node.isForkNode()|| node.isDecisionNode()){
+      target=this.findJoinNode(node);
+      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());
+        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);
+          }else{
+            var placeholderNode=self.nodeFactory.createPlaceholderNode(target);
+            tran.targetNode=placeholderNode;
+          }
+        }else{
+          tran.targetNode=target;
+        }
+      }else if (tran.getSourceNode().isForkNode()){
+        var joinNode=self.findJoinNode(tran.getSourceNode());
+        if (joinNode===target){
+          if (tran.getSourceNode().getOkTransitionCount()>2){
+            tran.getSourceNode().removeTransition(tran);
+          }else{
+            var placeholderNode=self.nodeFactory.createPlaceholderNode(target);
+            tran.targetNode=placeholderNode;
+          }
+        }else{
+          tran.targetNode=target;
+        }
+      }else{
+        tran.targetNode=target;
+      }
+    });
+  },
+  deleteTransition(transition){
+    var src=transition.getSourceNode();
+    src.removeTransition(transition);
+  },
+  deleteEmptyTransitions(transitionslist){
+    transitionslist.forEach(function(tran){
+      if (tran.getSourceNode().isForkNode()&& tran.getTargetNode().isJoinNode()){
+        tran.getSourceNode().removeTransition(tran);
+      }
+    });
+  },
+  findTransistionsToNode(matchingNode){
+    var transitionslist=[];
+    this.findTransistionsToNodeInternal(this.startNode,matchingNode,transitionslist);
+    return transitionslist;
+  },
+  findTransistionsToNodeInternal(node,matchingNode,transitionslist){
+    var self=this;
+    if (node.transitions){
+      node.transitions.forEach(function(tran){
+        if (tran.getTargetNode()===matchingNode){
+          transitionslist.push(tran);
+        }
+        self.findTransistionsToNodeInternal(tran.getTargetNode(),matchingNode,transitionslist);
+      });
+    }
+  }
+});
+
+
+export {Workflow};

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..d5dc4da
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js
@@ -0,0 +1,135 @@
+/*
+*    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 * as nodeHandler from '../domain/node-handler';
+import {SLAMapper} from "../domain/mapping-utils";
+
+import {MappingMixin,ConfigurationMapper} from "../domain/mapping-utils";
+var WorkflowXmlMapper= Ember.Object.extend({
+  nodeHandlerMap:null,
+  globalConfigHandler:null,
+  actionTypeResolver:null,
+  slaMapper: SLAMapper.create({}),
+  schemaVersions:null,
+  init: function() {
+    this.actionTypeResolver=nodeHandler.ActionTypeResolver.create({schemaVersions:this.schemaVersions});
+    this.set("globalConfigHandler",GlobalConfigHandler.create({}));
+    this.set("slaMapper",SLAMapper.create({}));
+    this.nodeHandlerMap=new Map();
+    this.nodeHandlerMap.set("start",nodeHandler.StartNodeHandler.create({}));
+    this.nodeHandlerMap.set("end",nodeHandler.EndNodeHandler.create({}));
+    this.nodeHandlerMap.set("action",nodeHandler.ActionNodeHandler.create({actionTypeResolver:this.actionTypeResolver}));
+    this.nodeHandlerMap.set("decision",nodeHandler.DecisionNodeHandler.create({}));
+    this.nodeHandlerMap.set("fork",nodeHandler.ForkNodeHandler.create({}));
+    this.nodeHandlerMap.set("join",nodeHandler.JoinNodeHandler.create({}));
+    this.nodeHandlerMap.set("kill",nodeHandler.KillNodeHandler.create({}));
+  },
+  getNodeHandler(type){
+    return this.nodeHandlerMap.get(type);
+  },
+  getGlobalConfigHandler(){
+    return this.globalConfigHandler;
+  },
+  getActionJobHandler(jobType){
+    return this.actionTypeResolver.getActionJobHandler(jobType);
+  },
+  handleSLAMapping(sla,workflowObj){
+    this.get("slaMapper").hanldeGeneration(sla,workflowObj);
+  },
+  handleSLAImport(workflow,infoJson){
+    this.slaMapper.handleImport(workflow,infoJson,"sla");
+  },
+  handleCredentialsGeneration(credentials,workflowObj){
+    if (credentials && credentials.length>0){
+      workflowObj["credentials"]={"credential":[]};
+      credentials.forEach(function(credential){
+        var credJson={_name:credential.name,_type:credential.type,property:[]};
+        if (credential.property){
+          credential.property.forEach(function(prop){
+            credJson.property.push({"name":prop.name,"value":prop.value});
+          });
+        }
+        workflowObj.credentials.credential.push(credJson);
+      });
+    }
+  },
+  handleCredentialImport(workflow,credJson){
+    if (!credJson || !credJson.credential){
+      return;
+    }
+    workflow.credentials.clear();
+    var credntialsJson=Ember.isArray(credJson.credential)?credJson.credential:[credJson.credential];
+    credntialsJson.forEach(function(cred){
+      var credential={
+        name:cred._name,
+        type:cred._type,
+        property:Ember.A([])
+      };
+      if (cred.property){
+        if (!Ember.isArray(cred.property)){
+          cred.property=[cred.property];
+        }
+        cred.property.forEach(function(property){
+          credential.property.push({"name":property.name,"value":property.value});
+        });
+      }
+      workflow.credentials.push(credential);
+    });
+  },
+  hanldeParametersGeneration(parameters,workflowObj){
+    if (!parameters || !parameters.configuration){
+      return;
+    }
+    if (parameters.configuration.property.length>0){
+      workflowObj.parameters={property:[]};
+    }
+    parameters.configuration.property.forEach(function(prop){
+      workflowObj.parameters.property.push({"name":prop.name,"value":prop.value});
+    });
+  },
+  handleParametersImport(workflow,parameters){
+    if (!parameters|| !parameters.property){
+      return;
+    }
+    workflow.parameters={"configuration":{property:[]}}
+    parameters.property.forEach(function(prop){
+      workflow.parameters.configuration.property.push({"name":prop.name,"value":prop.value});
+    });
+  }
+});
+var GlobalConfigHandler=Ember.Object.extend(MappingMixin,{
+  mapping:null,
+  configurationMapper:ConfigurationMapper.create({}),
+  init(){
+    this.mapping=[
+      {xml:"job-tracker",domain:"jobTracker"},
+      {xml:"name-node",domain:"nameNode"},
+      {xml:"configuration",customHandler:this.configurationMapper}
+    ];
+  },
+
+  handle(domainObject,nodeObj){
+    if (!domainObject){
+      return;
+    }
+    var globalObj={};
+    nodeObj["global"]=globalObj;
+    this.handleMapping(domainObject,globalObj,this.mapping);
+  }
+});
+export {WorkflowXmlMapper};

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/helpers/date-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/helpers/date-helper.js b/contrib/views/wfmanager/src/main/resources/ui/app/helpers/date-helper.js
new file mode 100644
index 0000000..58303c1
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/helpers/date-helper.js
@@ -0,0 +1,29 @@
+/*
+*    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.
+*/
+
+/*global moment:false */
+import Ember from 'ember';
+
+export function dateHelper(dateStr) {
+  var date = dateStr && new Date(dateStr);
+  if (!date || isNaN(date.getTime())) {
+    return "";
+  }
+  return [moment(date).format("MM/DD/YYYY hh:mm A")].join("");
+}
+
+export default Ember.Helper.helper(dateHelper);

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..a317a48
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/index.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<!--
+  ~    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.
+  -->
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Workflow Designer </title>
+    <link rel="shortcut icon" type="image/icon" href="assets/favicon.ico" />
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1"> {{content-for "head"}}
+    <link rel="stylesheet" href="assets/vendor.css">
+    <link rel="stylesheet" href="assets/oozie-designer.css"> {{content-for "head-footer"}}
+	<style>
+		body{background:#fff;}
+	</style>
+</head>
+
+<body>
+    {{content-for "body"}}
+    <script src="assets/vendor.js"></script>
+    <script src="assets/oozie-designer.js"></script>
+</body>
+<script type="text/javascript">
+var AmbariViewHelper = {
+    isAmbariView: function() {
+        return window.location.href.indexOf("/views/") > 0;
+    },
+    getViewInfo: function() {
+        var tokens = window.location.href.substring(window.location.href.indexOf("/views/") + 7).split("/");
+        var info = {
+            name: tokens[0],
+            version: tokens[1],
+            instance: tokens[2]
+        };
+        info.API_URL = ["/api/v1/views/", info.name, "/versions/", info.version, "/instances/" + info.instance].join("");
+        return info;
+    },
+    loadInstanceInfo: function() {
+        var viewInfo = this.getViewInfo();
+        $.ajax({
+            dataType: "json",
+            url: viewInfo.API_URL,
+            async: false,
+            success: function(result) {
+                Ember.ENV.instanceInfo = result;
+                // Update the API URL pointing to Ambari View Resource
+                Ember.ENV.API_URL = viewInfo.API_URL + "/resources/proxy";
+                Ember.ENV.FILE_API_URL = viewInfo.API_URL + "/resources/proxy/fileServices";
+            }
+        });
+    }
+};
+
+if (AmbariViewHelper.isAmbariView()) {
+    $('body').addClass("ambari-view");
+    AmbariViewHelper.loadInstanceInfo();
+}
+</script>
+
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/initializers/init.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/initializers/init.js b/contrib/views/wfmanager/src/main/resources/ui/app/initializers/init.js
new file mode 100644
index 0000000..c089258
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/initializers/init.js
@@ -0,0 +1,25 @@
+/*
+ *    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.
+ */
+
+export function initialize( /* application */ ) {
+    //application.inject('route', 'oozie', 'service:oozie-api');
+}
+
+export default {
+    name: 'init',
+    initialize
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/resolver.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/resolver.js b/contrib/views/wfmanager/src/main/resources/ui/app/resolver.js
new file mode 100644
index 0000000..d0b3de0
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/resolver.js
@@ -0,0 +1,20 @@
+/*
+ *    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 Resolver from 'ember-resolver';
+
+export default Resolver;

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/router.js b/contrib/views/wfmanager/src/main/resources/ui/app/router.js
new file mode 100644
index 0000000..1fcd633
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/router.js
@@ -0,0 +1,33 @@
+/*
+*    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 config from './config/environment';
+
+const Router = Ember.Router.extend({
+  location: config.locationType
+});
+
+Router.map(function () {
+  this.route('dashboard');
+  this.route('design');
+  this.route('designtest');
+  this.route('job');
+  this.route('connection-error');
+});
+
+export default Router;

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/routes/connection-error.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/connection-error.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/connection-error.js
new file mode 100644
index 0000000..8ea6f8e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/connection-error.js
@@ -0,0 +1,35 @@
+/*
+ *    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({
+  queryParams: {
+    current : { refreshModel : true}
+  },
+  previousLocation : '',
+  beforeModel (transition){
+    this.set('previousLocation',transition.queryParams.current);
+  },
+  model () {
+    var retryLocation = this.get('previousLocation');
+    if(!retryLocation){
+      retryLocation = '/#/dashboard';
+    }
+    return retryLocation;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..d0ef5e0
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js
@@ -0,0 +1,146 @@
+/*
+*    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({
+  history: Ember.inject.service(),
+  errorMessage : "Error",
+  queryParams: {
+    jobType: { refreshModel: true },
+    start: { refreshModel: true },
+    filter: { refreshModel: true }
+  },
+  actions: {
+    onShowJobDetails : function(params){
+      this.transitionTo('job',{
+        queryParams : {
+          id : params.id,
+          jobType : params.type,
+          from: null,
+          fromType: null
+        }
+      });
+    },
+    loading: function ( /*transition, originRoute*/ ) {
+      Ember.$("#loading").css("display", "block");
+      var app = this.controllerFor('application');
+      if (app.get('currentRouteName') !== "dashboard") {
+        return true;
+      }
+      return false;
+    },
+    error: function() {
+
+    },
+    doSearch (params){
+      this.get('history').setSearchParams(params);
+      Ember.$("#loading").css("display", "block");
+      this.search(params);
+    }
+  },
+  fetchJobs (url){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.get(url).done(function(res){
+      deferred.resolve(res);
+    }).fail(function(){
+      deferred.reject();
+    });
+    return deferred.promise;
+  },
+  search(params){
+    params = params || {};
+    var type = params.type || "wf",
+    start = Number(params.start || 1),
+    len = Number(params.len || Ember.ENV.PAGE_SIZE),
+    index = 0,
+    filter = params.filter || "",
+    API_URL = Ember.ENV.API_URL,
+    url = [API_URL,
+      "/v2/jobs?jobtype=", type,
+      "&offset=", start,
+      "&len=", len,
+      "&filter=", filter
+    ].join(""),
+    page = (start - 1) / len + 1;
+    return this.fetchJobs(url).catch(function(){
+      this.controllerFor('dashboard').set('model',{error : "Remote API Failed"});
+      Ember.$("#loading").css("display", "none");
+    }.bind(this)).then(function (res) {
+      if(!res){
+        return;
+      }
+      if (typeof res === "string") {
+        res = JSON.parse(res);
+      }
+      res.jobs = [];
+
+      if (res.workflows) {
+        res.areWfs = true;
+        res.type = "wf";
+        res.workflows.forEach(function (job) {
+          job.type = "wf";
+          res.jobs.push(job);
+        });
+      }
+      if (res.coordinatorjobs) {
+        res.areCoords = true;
+        res.type = "coords";
+        res.coordinatorjobs.forEach(function (job) {
+          job.type = "coordinatorjobs";
+          job.id = job.coordJobId;
+          job.appName = job.coordJobName;
+          res.jobs.push(job);
+        });
+      }
+      if (res.bundlejobs) {
+        res.areBundles = true;
+        res.type = "bundles";
+        res.bundlejobs.forEach(function (job) {
+          job.type = "bundlejobs";
+          job.id = job.bundleJobId;
+          job.appName = job.bundleJobName;
+          res.jobs.push(job);
+        });
+      }
+      res.pageSize = len;
+      res.pages = [];
+
+      while (index++ < (res.total / len)) {
+        res.pages.push({ index: index, active: page === index });
+      }
+
+      res.jobTypeValue = type;
+      res.filterValue = filter;
+      res.pageSize = len;
+      res.totalValue = res.total;
+      res.page = page;
+      res.start = start;
+      res.end = (start + res.jobs.length - 1);
+      res.time = new Date().getTime();
+      this.controllerFor('dashboard').set('model', res);
+      Ember.$("#loading").css("display", "none");
+      return res;
+    }.bind(this));
+  },
+  afterModel: function (model) {
+    Ember.$("#loading").css("display", "none");
+  },
+  model: function (params) {
+
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/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
new file mode 100644
index 0000000..cec0e9e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js
@@ -0,0 +1,25 @@
+/*
+ *    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);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/routes/designtest.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/designtest.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/designtest.js
new file mode 100644
index 0000000..052f998
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/designtest.js
@@ -0,0 +1,65 @@
+/*
+ *    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({
+  actions:{
+    showChart() {
+      //       jsPlumb.ready(function() {
+      // var a = $("#a");
+      // var b = $("#b");
+      var connectionColor="#777";
+      var lineWidth=1;
+      var stateMachineConnector = {
+        connector:"Bezier",
+        paintStyle:{lineWidth:3,strokeStyle:"#056"},
+        hoverPaintStyle:{strokeStyle:"#dbe300"},
+        endpoint:"Blank",
+        anchor:"Continuous",
+        overlays:[ ["PlainArrow", {location:1, width:15, length:12} ]]
+      };
+
+      var connection=jsPlumb.connect({
+          source:"a",
+          target:"b",
+          //connector:["Flowchart", { stub:1,alwaysRespectStubs :true,cornerRadius: 5 }],
+        //  connector:["Straight"],
+        //  connector:["StateMachine",{curviness:0}],
+          //connector: ["Bezier"],
+          paintStyle:{lineWidth:lineWidth,strokeStyle:connectionColor},
+          endpointStyle:{fillStyle:'rgb(243,229,0)'},
+          endpoint: ["Dot", {
+            radius: 1
+          }],
+          alwaysRespectStubs:true,
+          anchors: [["Bottom"],["Top"]]
+        //  anchors: [["Continuous"],["Continuous"]]
+      },stateMachineConnector);
+
+      connection.addOverlay([ "Label", {label:"<span>hello</span>", location:0.75, id:"myLabel" } ]);
+      // jsPlumb.connect({
+      //   source:"b",
+      //   target:"a"
+      // }, stateMachineConnector);
+
+      jsPlumb.repaintEverything();
+
+
+
+  }
+}
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js
new file mode 100644
index 0000000..0fbbaa2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js
@@ -0,0 +1,24 @@
+/*
+ *    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({
+    beforeModel() {
+        this.transitionTo('dashboard');
+    }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/routes/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/job.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/job.js
new file mode 100644
index 0000000..d849609
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/job.js
@@ -0,0 +1,84 @@
+/*
+ *    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({
+  history: Ember.inject.service(),
+  queryParams: {
+      jobType: { refreshModel: true },
+      id: { refreshModel: true },
+      from : {refreshModel: true},
+      fromType :{refreshModel : true}
+  },
+  from : null,
+  fromType : null,
+  getJobInfo (url){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.get(url).done(function(res){
+      deferred.resolve(res);
+    }).fail(function(){
+      deferred.reject();
+    });
+    return deferred.promise;
+  },
+  model : function(params){
+    return this.getJobInfo(Ember.ENV.API_URL+'/v2/job/'+params.id+'?show=info&timezone=GMT&offset=1&len='+Ember.ENV.PAGE_SIZE).catch(function(){
+        return {error : "Remote API Failed"};
+      }).then(function(response){
+      if (typeof response === "string") {
+          response = JSON.parse(response);
+      }
+      response.jobType = params.jobType;
+      return response;
+    });
+  },
+  afterModel : function (model, transition){
+    if(transition.queryParams.from){
+      this.set('from', transition.queryParams.from);
+      this.set('fromType',transition.queryParams.fromType);
+    }else{
+      this.set('from', null);
+      this.set('fromType', null);
+    }
+  },
+  actions : {
+    didTransition (){
+      this.controller.set('from', this.get('from'));
+      this.controller.set('fromType',this.get('fromType'));
+    },
+    onTabChange : function(tab){
+      this.set('currentTab', tab);
+      this.controller.set('currentTab',tab);
+    },
+    backToSearch : function(){
+      var params = this.get('history').getSearchParams();
+      if(null != params){
+        this.transitionTo('dashboard', {
+            queryParams: {
+                jobType: params.type,
+                start: params.start,
+                end: params.end,
+                filter: params.filter
+            }
+        });
+      }else{
+        this.transitionTo('dashboard');
+      }
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/services/file-browser.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/file-browser.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/file-browser.js
new file mode 100644
index 0000000..d5d8eb9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/file-browser.js
@@ -0,0 +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.
+*/
+
+import Ember from 'ember';
+
+export default Ember.Service.extend(Ember.Evented,{
+  setContext : function(context){
+    this.set('currentContext', context);
+  },
+  getContext : function(){
+    return this.get('currentContext');
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/services/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/history.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/history.js
new file mode 100644
index 0000000..f99f1da
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/history.js
@@ -0,0 +1,31 @@
+/*
+*    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({
+
+  lastSearch: null,
+
+  getSearchParams: function() {
+    return this.get('lastSearch');
+  },
+
+  setSearchParams : function(routeParams) {
+    this.set('lastSearch', routeParams);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/services/property-extractor.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/property-extractor.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/property-extractor.js
new file mode 100644
index 0000000..17ff9aa
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/property-extractor.js
@@ -0,0 +1,61 @@
+/*
+*    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({
+  simpleProperty : /^[A-Za-z_][0-9A-Za-z_]+$/,
+  dynamicProperty :  /^\${[A-Za-z_][0-9A-Za-z_]*}$/,
+  dynamicPropertyWithElMethod : /^\${[A-Za-z_][0-9A-Za-z_]*\((([A-Za-z_][0-9A-Za-z_]*)(,([A-Za-z_][0-9A-Za-z_]*))*)*\)}$/,
+  dynamicPropertyWithWfMethod : /^\${wf:[A-Za-z_][0-9A-Za-z_]*\((([A-Za-z_][0-9A-Za-z_]*)(,([A-Za-z_][0-9A-Za-z_]*))*)*\)}$/i,
+  hadoopEL : /^\${hadoop:.*}$/,
+  extractor : /\${.+?\}/g,
+  extract : function(property) {
+    var matches = property.match(this.get('extractor'));
+    var dynamicProperties = [];
+    if(null == matches) {
+      return dynamicProperties;
+    }
+    matches.forEach((match)=>{
+      if(this.get('dynamicProperty').test(match)){
+        dynamicProperties.push(match);
+      }
+    }.bind(this));
+    return dynamicProperties;
+  },
+  getProperties : function(currentValue, dynamicProperties) {
+    if( typeof currentValue === "object" ) {
+      Object.keys(currentValue).forEach((value, key)=> {
+        this.getProperties(currentValue[value], dynamicProperties);
+      }.bind(this));
+    } else {
+      if (typeof currentValue==="string"){
+        var extractedProperties = this.extract(currentValue);
+        extractedProperties.forEach((value)=>{
+          dynamicProperties.set(value,value);
+        });
+      }
+    }
+    return dynamicProperties;
+  },
+  getDynamicProperties : function(xml){
+    var x2js = new X2JS();
+    var workflowJSON = x2js.xml_str2json(xml);
+    var props= this.getProperties(workflowJSON, new Map());
+    return props;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.css
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.css b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.css
new file mode 100644
index 0000000..48232f5
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.css
@@ -0,0 +1,1335 @@
+/*
+ *    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.
+ */
+
+body {
+    background: #eee;
+    padding: 0;
+    margin: 0;
+}
+.padding0 {
+  padding: 0px;
+}
+.paddingtop7{
+  padding-top:7px;
+}
+.paddingtop10{
+  padding-top:10px;
+}
+.padding10{
+    margin-top: 10px;
+}
+.padding20{
+    margin-top: 20px;
+}
+.marginleft20{
+  margin-left: 20px !important;
+}
+#arrow{
+    top: 24%;
+    left: -22px;
+    margin-top: -11px;
+    border-right-color: #999 !important;
+    border-right-color: rgba(0, 0, 0, .25);
+    border-left-width: 0;
+    position: absolute;
+    display: block;
+    width: 0;
+    height: 0;
+    border-color: transparent;
+    border-style: solid;
+    border-width: 11px;
+}
+
+#cntnr,
+#container {
+    background: #ddd;
+}
+.disabled {
+    cursor:none;
+}
+#header {
+    white-space: nowrap;
+    background: #5bb75b;
+    background-position: 10px;
+    color: yellow;
+    height: 50px;
+    padding: 10px;
+    font-size: 20px;
+}
+.branch{
+    padding: 0px !important;
+    border: 0px !important;
+    background: inherit !important;
+}
+#sidebar .panel-body {
+    box-shadow: #bbb 3px 0 10px;
+}
+.condJoin {
+}
+.dummyAction{
+    margin:5%;
+}
+
+.branch input {
+    border: 0px;
+    text-align: center;
+}
+#sidebar .panel-body,
+#sidebar .panel-body,
+#content .designer-panel {
+}
+
+.designer-canvas {
+}
+
+#designer {
+    position: relative;
+}
+
+#wf_title {
+    border-bottom: 1px dotted #000;
+}
+
+.editable {
+    padding: 5px 10px;
+    border: 1px solid transparent;
+    background: transparent;
+    white-space: nowrap;
+    text-align: left;
+    margin: 0 2px;
+}
+
+.editable:focus,
+.editable:hover {
+    border: 1px solid #999;
+    background: #fff;
+    cursor: text;
+}
+
+.canDrag {
+    cursor: move;
+}
+
+.action {
+    float: left;
+    padding: 5px;
+    margin: 2px;
+    height: 60px;
+    line-height: 50px;
+    width: 62px;
+    font-size: small;
+    overflow: hidden;
+    text-align: center;
+}
+
+.node,
+.actions_list_left li:hover {
+    /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ffffff+0,e5e5e5+100;White+3D */
+    background: #ffffff;
+    /* Old browsers */
+    background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%);
+    /* FF3.6-15 */
+    background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%);
+    /* Chrome10-25,Safari5.1-6 */
+    background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%);
+    /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+    filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e5e5e5', GradientType=0);
+    /* IE6-9 */
+}
+
+.node {
+    text-align: center;
+    position: absolute;
+    left: 50%;
+    border: 1px solid #bbb;
+    overflow: visible;
+    background: transparent;
+    border: none;
+}
+
+.node-item{
+  background:#e5e5e5;
+  border:  1px solid #ABABAB;
+  z-index:4;
+
+}
+
+.action_node {
+    min-width: 195px;
+}
+
+.node:hover {
+}
+
+.fork,
+.join {
+    border-radius: 70px;
+    width: 40px;
+    height: 40px;
+    white-space: wrap;
+    padding-top: 10px;
+}
+
+.start,
+.end {
+    border-radius: 60px;
+    width: 40px;
+    height: 40px;
+    background: #fff;
+    line-height: 25px;
+    cursor: not-allowed;
+}
+
+.start {
+  top: 20px;
+  padding-left: 7px;
+  padding-top: 6px;
+}
+.kill{
+  border-radius: 5px;
+  min-width: 178px;
+  height: 38px;
+}
+.kill .fa-ban {
+  color: red;
+}
+.hrClass{
+    margin-bottom: 10px;
+    margin-top: 10px;
+}
+
+.kill-name{
+  padding-left: 40px;
+  margin-top: -35px;
+}
+
+.node .editable {
+    padding: 2px 5px;
+    width: 8em;
+    text-align: center;
+}
+
+.node .error{
+     border: 1px solid #a94442;
+}
+
+.connector_overlay {
+    transition: all .3s ease-in;
+    white-space: nowrap;
+    opacity: .8;
+    border: 1px solid #ddd;
+    background: #1a8cff;
+    border-radius: 30px;
+    width: 30px;
+    height: 30px;
+    line-height: 28px;
+    text-align: center;
+    cursor: pointer;
+    transform: scale(0.8);
+
+}
+
+.dataPlacement {
+    color: white;
+}
+.jsplumb-hover .connector_overlay,
+.connector_overlay:hover {
+    opacity: 1;
+}
+
+.node_actions {
+    transition: opacity 1s ease-in;
+    opacity: 0;
+    position: absolute;
+    white-space: nowrap;
+    border: 1px solid #999;
+    background: #E5E5E5;
+    border-radius: 3px;
+    min-width: 20px;
+    height: 28px;
+    cursor: pointer;
+}
+.node_actions i{
+  padding: 5px;
+}
+.node_properties {
+    border-radius: 30px;
+    cursor: pointer;
+}
+.node_properties:hover {
+    cursor: pointer;
+}
+.decision_node .node_properties {
+  margin-top: -16px;
+}
+.decisionNodeError{
+    position: relative;
+    left: 50px;
+ }
+.action-node {
+    border-radius: 5px;
+    height: 38px;
+}
+.dummy {
+    width: 160px;
+    height: 50px;
+    box-shadow: none;
+}
+.node_left .fa-trash-o{
+    color: red;
+}
+.node_left {
+  right: -45px;
+  top: -61%;
+}
+.decision_node .node_left{
+    transform: rotate(315deg) scale(1.4);
+    right: -50px;
+    top: -126%;
+}
+.node_left:hover {
+}
+.nodeEnd{
+    top:15%;
+    position: relative;
+}
+.nodeStart{
+    right:5%;
+    position: relative;
+}
+.node_bottom {
+
+    bottom: 50%;
+    left: 50%;
+    z-index: 5;
+    transform: translate(-50%, -20%) scale(0.8);
+    opacity: 1;
+        border-radius: 3px;
+    width: 40px;
+    height: 24px;
+}
+.fork .node_bottom {
+    top: 80%;
+
+}
+.node_bottom_actions{
+  position: absolute;
+  background: #E5E5E5;
+  white-space: nowrap;
+}
+.node:hover .node_actions {
+    opacity: 1;
+}
+
+.action_node {
+    border-radius: 4px;
+}
+
+input:invalid {
+    border: 1px solid red;
+}
+
+.fa-exclamation-triangle {
+    color: red;
+}
+
+.actions_list_left {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+}
+
+.actions_list_left li.disabled {
+    cursor: not-allowed;
+    background: #eee;
+    color: #ccc;
+}
+
+.actions_list_left li {
+    background: #fff;
+    width: 60px;
+    padding: 10px;
+    border: 1px solid silver;
+    border-radius: 5px;
+    margin: 2px 0;
+    cursor: move;
+    z-index: 1000;
+    display: inline-block;
+    position: relative;
+    text-align: center;
+}
+
+#sidebar .actions_list_left li:before {
+    content: '.. .. .. ..';
+    width: 10px;
+    display: block;
+    line-height: 4px;
+    position: absolute;
+    color: #aaa;
+    left: 5px;
+    top: 5px;
+}
+
+.control_flow_node,
+.control_flow li:hover {
+    /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#fdfeea+0,e8f135+100 */
+    /*background: #fdfeea;*/
+    /* Old browsers */
+    /*background: -moz-linear-gradient(top, #fdfeea 0%, #e8f135 100%);*/
+    /* FF3.6-15 */
+    /*background: -webkit-linear-gradient(top, #fdfeea 0%, #e8f135 100%);*/
+    /* Chrome10-25,Safari5.1-6 */
+    /*background: linear-gradient(to bottom, #fdfeea 0%, #e8f135 100%);*/
+    /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+    /*filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#fdfeea', endColorstr='#e8f135', GradientType=0);*/
+    /* IE6-9 */
+}
+.decision-condition {
+  white-space: nowrap;
+  width: 10em;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  border: 1px solid #D0D0D0;
+  border-radius: 3px;
+  background-color: #F5F5F5;
+  padding: 3px;
+  font-size: 11px;
+  opacity: 0.8;
+}
+.decision_node {
+  transform: rotate(45deg) scale(.7);
+  width: 60px;
+  height: 60px;
+  padding: 5px;
+  float: right;
+  margin: 0 2px;
+}
+.decision-data-wrapper{
+  transform: rotate(-45deg) scale(1.3); ;
+}
+.decision_node_data .editable{
+  margin-right: 10px;
+}
+.decision_node_data {
+  padding-right: 31px;
+  float: right;
+  margin: 0 2px;
+}
+.fork_node_data {
+  float: right;
+  margin-top: -15px;
+}
+.fork_node_data .editable {
+  margin-right: 5px;
+}
+.decision_node .content {
+    text-align: center;
+    position: absolute;
+    padding: 0 5px;
+    width: 120px;
+    height: 70px;
+    transform: rotate(-45deg) scale(1.2) translate(-13%, 30%);
+    white-space: nowrap;
+}
+
+.breadcrumb {
+    margin: 0;
+}
+
+.collapse.width {
+    height: auto;
+    -webkit-transition: width 0.35s ease;
+    -moz-transition: width 0.35s ease;
+    -o-transition: width 0.35s ease;
+    transition: width 0.35s ease;
+}
+
+.highlighter-always {
+    opacity: 1;
+    animation-name: highlighter;
+    animation-duration: 1s;
+    animation-iteration-count: infinite;
+    animation-timing-function: ease-out;
+}
+
+@keyframes highlighter {
+    0% {
+        transform: scale(1)
+    }
+    50% {
+        transform: scale(1.5)
+    }
+    100% {
+        transform: scale(1)
+    }
+}
+
+.control_flow li._fork {
+    border-radius: 50px;
+    margin: 4px 8px;
+}
+
+.control_flow li.switch {
+    border-radius: 0px;
+    transform: rotate(45deg) translate(0%, -0%) scale(.9);
+}
+
+.active_drag {
+    box-shadow: 5px 5px 5px #aaa;
+}
+
+.can_be_dropped {
+    color: green;
+    border: 1px solid green;
+}
+
+.can_be_dropped:after {
+    font-family: FontAwesome;
+    content: "\f00c";
+    font-size: 25px;
+    display: block;
+    position: absolute;
+    color: #69be28;
+    top: -20px;
+    left: 20px;
+}
+
+.tooltip-inner {
+    white-space: pre;
+    max-width: none;
+}
+
+.action_node_data,
+.action_node_button {
+    padding: 5px;
+    float: left;
+    margin: 0 2px;
+}
+
+.action_node_button:hover {
+    background: #fff;
+}
+
+.caseLabel {
+    padding: 5px;
+    background: rgba(255, 255, 255, .8);
+    font-size: small;
+    border-radius: 20px;
+    border: 1px solid #ccc;
+    white-space: nowrap;
+    color: blue;
+}
+
+#content,
+#sidebar {
+    padding: 0;
+    margin: 0;
+    float: left;
+    position: relative;
+    transition: left .6s cubic-bezier(0.175, 0.885, 0.320, 1.275);
+}
+
+#sidebar {
+    width: 240px;
+    text-align: center;
+    position: absolute;
+    z-index: 1;
+    top: 89px;
+}
+
+#sidebar:after {
+    content: "\f101";
+    position: absolute;
+    right: -10px;
+    top: 50%;
+    font-family: FontAwesome;
+    background: #aaa;
+    color: #fff;
+    padding: 5px;
+}
+
+.expanded {
+    left: 0px;
+}
+
+.expanded:after {
+    content: "\f100" !important;
+}
+
+.collapsed {
+    left: -215px;
+}
+
+.title-btn,
+.title-btn:hover {
+    border: 0;
+    background: transparent;
+}
+
+.back_button {
+    height: 30px;
+    background-color: #fff;
+    position: relative;
+    margin-left: 13px;
+    border-radius: 5px;
+    border: 1px solid #ccc;
+}
+
+.back_button:before {
+    content: "";
+    position: absolute;
+    top: -1px;
+    left: -13px;
+    border-style: solid;
+    border-width: 15px 15px 15px 0;
+    border-color: transparent #ccc transparent transparent;
+}
+
+.back_button:after {
+    content: "";
+    position: absolute;
+    top: 0px;
+    left: -12px;
+    border-style: solid;
+    border-width: 14px 14px 14px 0;
+    border-color: transparent #fff transparent transparent;
+}
+
+.back_button > a {
+    display: block;
+    text-decoration: none;
+    text-align: center;
+    color: #000;
+    padding: 0 10px 0 5px;
+    line-height: 27px;
+    font-size: smaller;
+}
+
+.ambari-view #header {
+    display: none;
+}
+
+.ambari-view #content {
+    padding: 0;
+}
+
+.ambari-view #sidebar {
+    top: 39px;
+}
+
+.ambari-view body {
+    background: #fff;
+}
+
+.messageDiv {
+    position: absolute;
+    left: 40%;
+    top: 100px;
+    z-index: 1;
+}
+
+.workflow-error {
+    top:50px;
+    left: 75%;
+    /*width:50%;*/
+    z-index: 1;
+}
+
+#action_properties_dialog .modal-body {
+    max-height: 350px;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+
+#action_properties_dialog .container,
+#global_properties_dialog .container {
+    max-width: 180%;
+}
+
+#action_properties_dialog .blank-form {
+    right: 15px;
+    position: relative;
+}
+
+#action_properties_dialog .modal-dialog,
+#workflow_sla_dialog .modal-dialog,
+#global_properties_dialog .modal-dialog {
+    width: 800px;
+}
+#collapseOne{
+    margin: 10px;
+}
+.panel-heading {
+    padding: 4px 15px;
+}
+
+#action_properties_dialog .panel-default > .panel-heading,
+#global_properties_dialog .panel-default > .panel-heading,
+#workflow_sla_dialog .panel-default > .panel-heading,
+#workflow_credentials_dialog .panel-default > .panel-heading,
+#configureWorkfowModal .panel-default > .panel-heading,
+ .whiteLabel, .whiteLabel:hover, .whiteLabel:focus, .whiteLabel:visited, .whiteLabel:active {
+    background-color: #5bb75b;
+    color: #fff;
+}
+.btn-primary{
+    background-color: #5bb75b !important;
+    border-color: #289028 !important;
+    color: #fff;
+}
+.btn-primary:visited,.btn-primary:focus,.btn-primary:active,.btn-primary.active{
+    background-color: #5bb75b !important;
+    border-color: #289028 !important;
+    color: #fff;
+}
+.btn-primary:hover{
+  background-color: #289028 !important;
+  border-color: #289028 !important;
+  color: #fff;
+}
+._actions_popup {
+    padding: 4px;
+}
+
+._actions_popup .control_flow {
+    padding-left: 20%;
+}
+
+._actions_popup ul {
+    padding: 0;
+    margin: 0;
+}
+
+._actions_popup h4 {
+    font-size: 10px;
+    font-weight: bold;
+}
+
+._actions_popup li {
+    list-style: none;
+    float: left;
+    width: 53px;
+    height: 50px;
+    border: 1px solid silver;
+    margin: 3px;
+    padding: 10px;
+    text-align: center;
+    font-size: 11px;
+    border-radius: 6px;
+    cursor: pointer;
+}
+.labels {
+    width:70px;
+}
+.error{
+    border: 2px solid red;
+}
+.validated{
+    border: 2px solid #4cae4c;
+}
+.notification {
+    width:40%;
+    left:50%;
+    position: relative;
+}
+.redColor{
+    color: red;
+}
+.killNode{
+    width: 150px;
+}
+.zoom-buttons {
+  position: absolute;
+  top: 9px;
+  right: 2%;
+}
+.legend {
+    right: 1%;
+
+}
+.globlaPropetiesInfo{
+        width: 80%;
+    left: 10%;
+    position: relative;
+}
+.zoom-buttons .btn {
+    font-size: 8px;
+}
+
+.requiredField {
+    color: red;
+}
+#search-bar .twitter-typeahead {
+    position: inherit !important;
+}
+#search-bar .tt-hint {
+  display: none !important;
+}
+#search-bar .bootstrap-tagsinput {
+    width: 260px;
+    border-radius: 0px;
+    line-height: 20px;
+    vertical-align: top;
+    height: 30px;
+    overflow-y: auto;
+}
+#search-bar .bootstrap-tagsinput .label-info{
+    background-color : #5bb75b;
+}
+#search-bar .tt-menu {
+    position: absolute;
+    top: 100%;
+    left: inherit !important;
+    z-index: 100;
+    border: 1px solid rgba(0,0,0,0.2);
+    margin-top: 7px;
+    background-color: white;
+    width: 60% !important;
+    padding: 0 5px;
+}
+#job-detail-app-path{
+  overflow-x: scroll;
+}
+
+#search-bar .search-icon {
+  display: inline-block;
+  border: 1px solid #ccc;
+  padding: 4px 10px;
+  border-left: 0px;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+
+#startDate, #endDate {
+  height: 30px;
+  width: 162px;
+}
+
+.jobTitle {
+  height: 24px;
+  margin-left: 10px;
+  line-height: 30px;
+}
+
+.info {
+    float: left;
+    margin-right: 20px;
+    color: #777;
+    padding-top: 4px;
+}
+
+.pages {
+    margin-right: 40px;
+}
+
+.listing-footer {
+  border-top: 1px solid #d2d2d2;
+  border-bottom: 1px solid #d2d2d2;
+  padding: 3px 0px;
+  margin: 0 0 5px 0;
+}
+
+.page-selector {
+  padding: 4px 12px;
+  border-radius: 0px;
+}
+
+.listing thead {
+    background: #f5f5f5;
+}
+
+.listing th {
+  border-left : 1px solid #ddd;
+  border-bottom: 1px solid #ddd !important;
+}
+
+.listing tr th:first-child {
+  border-left: 0;
+}
+
+.listing > tbody > tr > td {
+  vertical-align: middle;
+  padding: 5px;
+  border-left: 0;
+  border-right: 0;
+}
+
+.job-listing > tbody > tr > td {
+  border-bottom: 1px solid #ddd;
+}
+
+
+.pointer {
+  cursor: pointer;
+}
+
+#job-details .nav-tabs {
+  background: #eee;
+  margin-bottom: 10px;
+}
+
+.preview pre.prettyprint {
+  border: none;
+  background: #fff;
+}
+
+.preview pre {
+  border: none;
+  background: #fff;
+}
+
+.date-picker {
+  position: relative;
+}
+
+.actions-col .loading-container{
+  position: relative;
+}
+
+#bulk-action-loader .loading-container{
+  position: relative;
+}
+
+.decisionNodeHandler {
+    left: 10%;
+    bottom: 30%;
+    position: relative;
+}
+
+.decisionBox {
+    right: 10px;
+    top: 13%;
+    width:75px;
+    position: relative;
+}
+
+.pages .open .dropdown-menu {
+  max-height: 120px;
+  overflow-y: scroll;
+  min-width : 75px;
+  width : 75px;
+}
+
+#action-details .panel-heading {
+  padding: 10px 15px;
+}
+
+#bulk-action-button .dropdown-menu li .fa {
+  margin-right: 10px;
+}
+
+#dashboard, #dashboard .panel, .panel-heading, .panel-body {
+  border-radius: 0px;
+}
+
+#job-details, #job-details .panel, .panel-heading, .panel-body {
+  border-radius: 0px;
+}
+
+#dashboard .listing-error{
+  text-align: center;
+}
+
+#dashboard .panel {
+  border: 0;
+  border-bottom: 1px solid #ddd;
+}
+
+#loading {
+    position: absolute;
+    top: 90px;
+    left: 0;
+    display: none;
+    width: 100vw;
+    height: 80vh;
+    overflow: hidden;
+    z-index: 1;
+}
+
+.loader img {
+  height: 40px;
+  width: 50px;
+}
+
+#search-table {
+    margin-bottom: 0px;
+}
+
+#search-table .bulk-actions-buttons {
+    margin-left: -124px;
+    margin-top: 3px;
+    position: fixed;
+    transition: all .5s ease;
+}
+
+#search-table .bulk-actions-buttons:before {
+    display: block;
+    content: "";
+    width: 0;
+    height: 0;
+    left: -10px;
+    top: 10px;
+    border: 5px solid transparent;
+    border-right: 10px solid #666;
+    position: absolute;
+}
+
+#search-table .bulk-actions-buttons.shown {
+    margin-left: 30px;
+}
+
+#search-table .actions-col {
+      white-space: nowrap;
+      text-align: center;
+      min-width: 150px;
+  }
+
+  .btn-kill:hover,
+  .btn-kill:focus {
+      background: #d9534f;
+      color: #fff;
+      border-color: red;
+  }
+
+  .actions-col .btn {
+      color: gray;
+      cursor: not-allowed;
+      opacity: .5;
+      font-size: 10px;
+  }
+
+  .actions-col .btn.isOn {
+      color: #000;
+      cursor: pointer;
+      opacity: 1;
+  }
+  .pages .btn {
+      /*color: #5bb75b;*/
+  }
+
+  .pages .btn.disabled {
+      color: gray;
+  }
+
+  .pages .btn-primary {
+      color: #fff;
+  }
+  .cbox {
+      width: 20px;
+  }
+
+  .main-panel {
+      padding: 0px;
+  }
+
+  #dashboard .main-panel {
+    padding: 5px;
+  }
+
+  .first-col {
+      text-align: center;
+  }
+
+
+
+.DONEWITHERROR,
+.FAILED,
+.KILLED {
+    color: #d9534f;
+}
+
+.RUNNING {
+    color: green;
+}
+
+.PAUSED,
+.PAUSEDWITHERROR,
+.PREPPAUSED,
+.RUNNINGWITHERROR,
+.SUSPENDED,
+.SUSPENDEDWITHERROR {
+    color: #f0ad4e;
+}
+
+.SUCCEEDED {
+    color: #5cb85c;
+}
+
+.mb0 {
+  margin-bottom: 0;
+}
+
+.pb5 {
+    padding-bottom: 5px;
+}
+
+.navbar-header {
+  width: 100%;
+}
+
+#create-new-button {
+  float: right;
+  padding-top: 8px;
+}
+
+.width100Per{
+  width: 100%;
+}
+.hdfs-browse{
+  max-height: 500px;
+  overflow: scroll;
+}
+#wf_title{
+    margin-top: 10px;
+    float: left;
+    width: 115px;
+    font-size: 12px;
+}
+.backto-dashboard{
+  text-decoration: blink !important;
+}
+.file-upload-control input[type="file"]{
+  width: 200px;
+  display: inline;
+  border: 1px solid #ccc;
+}
+.file-upload-control  input[type="button" i], input[type="submit" i], input[type="reset" i], input[type="file" i]::-webkit-file-upload-button, button {
+    padding: 6px 12px;
+    border-radius: 4px;
+    background-color: #fff;
+    line-height: 1.42857143;
+    border: none;
+}
+.close-icon{
+  font-size: 18px;
+  font-weight: bold;
+  line-height: 1;
+  text-shadow: 0 1px 0 #fff;
+  color: #AFAFAF;
+  background: transparent;
+  padding: 3px;
+}
+#flow-designer{
+  position: relative;
+  top:10%;
+}
+.designer-main-panel{
+   position: relative;
+   width: 100%;
+   border: none;
+   height: 0px;
+}
+.connector_overlay_new {
+    white-space: nowrap;
+    border: 1px solid #ddd;
+    background: #E5E5E5;
+    border-radius: 30px;
+    width: 24px;
+    height: 24px;
+    line-height: 24px;
+    text-align: center;
+    cursor: pointer;
+    transform: scale(0.8);
+    font-size: 12px;
+}
+.connector_overlay_new:hover .node_actions{
+    opacity: 1;
+}
+.placeholder-node{
+  width:1px;
+  height: 1px;
+  background: transparent;
+  padding-left: 0px;
+  padding-right: 0px;
+  margin-left: 4px;
+  /*  transform: translate(0%, -6%);*/
+}
+.decision_end{
+  width: 10px;
+  height: 10px;
+  border-radius: 16px;
+}
+#decision-properties-table {
+  width: 70%;
+  margin-left: 50px;
+}
+.preview-xml{
+  border: none;
+  padding: 8px;
+}
+.workflow-actions-pop{
+  width: 300px;
+}
+#killnodes-container{
+  width: 300px;
+  height: 100px;
+  padding: 5px;
+  border-radius: 3px;
+  /*border: 2px solid #ccc;*/
+}
+.decision-add-branch-popover{
+  position: absolute;
+  left: 44px;
+  top: -7px;
+  z-index: 5;
+}
+
+.jsplumb-connector { z-index:1; }
+.jsplumb-endpoint { z-index:2; }
+.jsplumb-overlay { z-index:3; }
+#selector-content .panel-body{
+    width:400px;
+}
+
+
+
+.node-test {
+    background-color: white;
+    border: 3px solid #346789;
+    color: black;
+    font-family: helvetica;
+    font-size: 0.8em;
+    height: 12em;
+    opacity: 0.8;
+    padding: 0.5em;
+    position: absolute;
+    width: 14em;
+    z-index: 20;
+    text-align:center;
+}
+
+.dragActive {
+    border: 3px solid #346789;
+}
+.decisionSplit {
+    border-radius: 24px;
+    width: 24px;
+    height: 24px;
+    left: 70% !important;
+    top: 67% !important;
+    transform:rotate(315deg) !important;
+}
+.forkSplit {
+    border-radius: 24px;
+    width: 24px;
+    height: 18px;
+    left: 50% !important;
+    top: 75% !important;
+}
+.forkAction{
+}
+.control_flow_node {
+    cursor: not-allowed;
+}
+.join {
+background: #fff;
+}
+.default-condition{
+  background-color: blue;
+}
+.query-text-area {
+  width: 540px;
+}
+.decisionText{
+    position: absolute;
+    transform: rotate(315deg);
+    top: 30%;
+    left: 5px;
+    right: 0px;
+}
+.decisionIcon{
+    position: relative;
+    right: 5px;
+}
+.actionNodes li{
+    padding: 10px 0px !important;
+    height: auto;
+}
+.dr_action_fork{
+    width: 45px !important;
+    height: 45px !important;
+    padding: 13px 0px !important;
+}
+.dr_action_switch{
+    width: 50px !important;
+    height: 45px !important;
+    padding: 10px 0px !important;
+}
+.paddingClass{
+    padding-top: 0.5%;
+}
+.margin0{
+    margin-bottom: 0px;
+}
+.editor-icon-title span{
+  padding-left: 5px;
+}
+.icon_map_red{
+  background: url(data:image/png;base64,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)
+}
+.node_actions i{
+  border-right: 1px solid #ababab;
+  border-radius: 0px;
+  min-width: 26px;
+}
+.node_actions i:last-child {
+  border-right:none;
+}
+.elipsisClass{
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -o-text-overflow: ellipsis;
+    white-space: nowrap;
+    width: 30%;
+}
+.wf-path {
+    font-size: 12px;
+    float: left;
+    color: gray;
+    margin-top: 17px;
+    max-width: 150px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+}
+.cred-type{
+  font-size: 12px;
+  color: gray;
+  margin-left: 5px;
+}
+.labelCheckbox{
+    padding-left:35px !important;
+}
+.file-op-setting{
+   padding-left: 105px;
+}
+.rightAlign{
+    text-align: left !important;
+}
+.bottom-margin-zero{
+    margin-bottom: 5px !important;
+}
+#credentials_config .fa-trash-o{
+    color: red;
+    cursor: pointer;
+}
+.check-class{
+    padding-left: 3%;
+}
+.popover-title{
+  background-color:#fff
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7742e7f/contrib/views/wfmanager/src/main/resources/ui/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/application.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/application.hbs
new file mode 100644
index 0000000..29fb89e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/application.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+ {{#header-logo-user-bar}}{{/header-logo-user-bar}}
+<div id="cntnr" class="cntnr">
+    {{outlet}}
+</div>