Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 f1cedfd89 -> d6affb415


AMBARI-19385:Resolve variables in workflow if workflow pathin coordinator 
contains variables. (Padma Priya via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d6affb41
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d6affb41
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d6affb41

Branch: refs/heads/branch-2.5
Commit: d6affb4153d40fd7e9a3da11a68f7f79df5f0d0f
Parents: f1cedfd
Author: Gaurav Nagar <[email protected]>
Authored: Fri Jan 6 13:01:42 2017 +0530
Committer: Gaurav Nagar <[email protected]>
Committed: Fri Jan 6 13:02:39 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/bundle-config.js          |  46 ++++++-
 .../resources/ui/app/components/coord-config.js |  55 +++++---
 .../ui/app/components/flow-designer.js          |   4 +-
 .../resources/ui/app/components/job-config.js   |  55 ++++++--
 .../ui/app/services/property-extractor.js       |   4 +
 .../app/templates/components/coord-config.hbs   |   6 +-
 .../ui/app/templates/components/job-config.hbs  | 135 ++++++++++++++-----
 7 files changed, 232 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
index 122b956..c6a24b8 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
@@ -134,6 +134,7 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
   importBundle (filePath){
     this.set("bundleFilePath", filePath);
     this.set("isImporting", false);
+    filePath = this.appendFileName(filePath, 'bundle');
     var deferred = this.getFromHdfs(filePath);
     deferred.promise.then(function(data){
       this.getBundleFromXml(data);
@@ -172,20 +173,37 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
   },
   getJobProperties(coordinatorPath){
     var deferred = Ember.RSVP.defer();
+    coordinatorPath = this.appendFileName(coordinatorPath, 'coord');
     this.getFromHdfs(coordinatorPath).promise.then((coordinatorXml)=>{
       var x2js = new X2JS();
       var coordProps = 
this.get('propertyExtractor').getDynamicProperties(coordinatorXml);
       var coordinatorJson = x2js.xml_str2json(coordinatorXml);
       var workflowPath = 
coordinatorJson['coordinator-app']['action']['workflow']['app-path'];
-      this.getFromHdfs(workflowPath).promise.then((workflowXml)=>{
-        var workflowProps = 
this.get('propertyExtractor').getDynamicProperties(workflowXml);
-        
deferred.resolve(Array.from(coordProps.values()).concat(Array.from(workflowProps.values())));
-      });
+      if(this.get('propertyExtractor').containsParameters(workflowPath)){
+        deferred.resolve(Array.from(coordProps.values()));
+      }else{
+        workflowPath = this.appendFileName(workflowPath, 'wf');
+        this.getFromHdfs(workflowPath).promise.then((workflowXml)=>{
+          var workflowProps = 
this.get('propertyExtractor').getDynamicProperties(workflowXml);
+          
deferred.resolve(Array.from(coordProps.values()).concat(Array.from(workflowProps.values())));
+        });
+      }
     }.bind(this)).catch((e)=>{
       deferred.reject({trace :e, path: coordinatorPath});
     });
     return deferred;
   },
+  appendFileName(filePath, type){
+    if(!filePath.endsWith('.xml') && type === 'bundle'){
+      return filePath = `${filePath}/bundle.xml`;
+    }else if(!filePath.endsWith('.xml') && type === 'coord'){
+      return filePath = `${filePath}/coordinator.xml`;
+    }else if(!filePath.endsWith('.xml') && type === 'wf'){
+      return filePath = `${filePath}/workflow.xml`;
+    }else{
+      return filePath;
+    }
+  },
   actions : {
     closeFileBrowser(){
       this.set("showingFileBrowser", false);
@@ -261,20 +279,36 @@ export default Ember.Component.extend(Ember.Evented, 
Validations, {
       var propertyPromises = [];
       this.$('#loading').show();
       this.get('bundle.coordinators').forEach((coordinator) =>{
+        
if(this.get('propertyExtractor').containsParameters(coordinator.appPath)){
+          return;
+        }
         var deferred = this.getJobProperties(coordinator.appPath);
         propertyPromises.push(deferred.promise);
       }, this);
       Ember.RSVP.Promise.all(propertyPromises).then(function(props){
         var combinedProps = [];
-        props.forEach((prop)=>{
+        var excludedProps = [];
+        props.forEach((prop, index)=>{
+          var coordinator = this.get('bundle.coordinators').objectAt(0);
+          if(coordinator.configuration && coordinator.configuration.property){
+            coordinator.configuration.property.forEach((config) => {
+              var idx = prop.indexOf('${'+config.name+'}');
+              if(idx >= 0){
+                excludedProps.push('${'+config.name+'}');
+              }
+            });
+          }
           combinedProps = combinedProps.concat(prop);
         });
         var dynamicProperties = 
this.get('propertyExtractor').getDynamicProperties(bundleXml);
         combinedProps.forEach((prop)=>{
+          if(excludedProps.indexOf(prop) >= 0){
+            return;
+          }
           dynamicProperties.set(prop, prop);
         });
         this.$('#loading').hide();
-        var configForSubmit = {props : dynamicProperties, xml : bundleXml, 
params : this.get('bundle.parameters')};
+        var configForSubmit = {props : Array.from(dynamicProperties.values(), 
key => key), xml : bundleXml, params : this.get('bundle.parameters')};
         this.set("bundleConfigs", configForSubmit);
         this.set("showingJobConfig", true);
       }.bind(this)).catch(function(e){

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
index 904901c..743a163 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
@@ -247,6 +247,7 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
     return deferred;
   },
   importCoordinator (filePath){
+    filePath = this.appendFileName(filePath, 'coord');
     this.set("coordinatorFilePath", filePath);
     this.set("isImporting", false);
     var deferred = this.readFromHdfs(filePath);
@@ -277,6 +278,15 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
     });
     return deferred;
   },
+  appendFileName(filePath, type){
+    if(!filePath.endsWith('.xml') && type === 'coord'){
+      return filePath = `${filePath}/coordinator.xml`;
+    }else if(!filePath.endsWith('.xml') && type === 'wf'){
+      return filePath = `${filePath}/workflow.xml`;
+    }else{
+      return filePath;
+    }
+  },
   getCoordinatorFromXml(coordinatorXml){
     var coordinatorXmlImporter = CoordinatorXmlImporter.create({});
     var coordinatorObj = 
coordinatorXmlImporter.importCoordinator(coordinatorXml);
@@ -399,27 +409,41 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
         this.set('showErrorMessage', true);
         return;
       }
-      this.$('#loading').show();
-      var deferred = 
this.readFromHdfs(this.get('coordinator.workflow.appPath'));
+      var coordGenerator = 
CoordinatorGenerator.create({coordinator:this.get("coordinator")});
+      var coordinatorXml = coordGenerator.process();
+      var configForSubmit={props:Ember.A([]), 
xml:coordinatorXml,params:this.get('coordinator.parameters'), 
errors:Ember.A([])};
+      this.set("coordinatorConfigs", configForSubmit);
+      this.set("showingJobConfig", true);
+      var dynamicProperties = 
this.get('propertyExtractor').getDynamicProperties(coordinatorXml);
+      
this.get('coordinatorConfigs.props').pushObjects(Array.from(dynamicProperties.values(),
 key => key));
+      var path = this.get('coordinator.workflow.appPath');
+      if(this.get('propertyExtractor').containsParameters(path)){
+        this.set('parameterizedWorkflowPath', path);
+        this.set('containsParameteriedPaths', true);
+        return;
+      }
+      this.send('extractProperties', path);
+    },
+    extractProperties(workflowPath){
+      this.set("coordinatorConfigs.errors", Ember.A([]));
+      workflowPath = this.appendFileName(workflowPath, 'wf');
+      var deferred = this.readFromHdfs(workflowPath);
       deferred.promise.then(function(data){
         var x2js = new X2JS();
         var workflowJson = x2js.xml_str2json(data);
         this.set('workflowName', workflowJson["workflow-app"]._name);
         var workflowProps = 
this.get('propertyExtractor').getDynamicProperties(data);
-        var coordGenerator = 
CoordinatorGenerator.create({coordinator:this.get("coordinator")});
-        var coordinatorXml = coordGenerator.process();
-        var dynamicProperties = 
this.get('propertyExtractor').getDynamicProperties(coordinatorXml);
+        var dynamicProperties = this.get('coordinatorConfigs.props');
         workflowProps.forEach((prop)=>{
-          dynamicProperties.set(prop, prop);
-        });
-        this.$('#loading').hide();
-        var 
configForSubmit={props:dynamicProperties,xml:coordinatorXml,params:this.get('coordinator.parameters')};
-        this.set("coordinatorConfigs", configForSubmit);
-        this.set("showingJobConfig", true);
+          var name = prop.trim().substring(2, prop.length-1);
+          if(dynamicProperties.indexOf(prop)>=0 || 
this.get('coordinator.workflow.configuration.property') && 
this.get('coordinator.workflow.configuration.property').findBy('name', name)){
+              return;
+          }
+          dynamicProperties.pushObject(prop);
+        }, this);
+        this.set('containsParameteriedPaths', false);
       }.bind(this)).catch(function(e){
-        this.set('workflowProps',[]);
-        this.$('#loading').hide();
-        this.get("errors").pushObject({'message' : 'Could not process workflow 
from ' + this.get('coordinator.workflow.appPath')});
+        this.get("coordinatorConfigs.errors").pushObject({'message' : 'Could 
not process workflow from ' + this.get('coordinator.workflow.appPath')});
         throw new Error(e);
       }.bind(this));
     },
@@ -541,7 +565,8 @@ export default Ember.Component.extend(Validations, 
Ember.Evented, {
     },
     showWorkflowName(){
       this.set('workflowName', null);
-      var deferred = 
this.readFromHdfs(this.get('coordinator.workflow.appPath'));
+      var path = this.appendFileName(this.get('coordinator.workflow.appPath'), 
'wf');
+      var deferred = this.readFromHdfs(path);
       deferred.promise.then(function(data){
         var x2js = new X2JS();
         var workflowJson = x2js.xml_str2json(data);

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
index 3454374..66123d0 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
@@ -300,13 +300,13 @@ export default Ember.Component.extend(FindNodeMixin, 
Validations, {
   importWorkflow(filePath){
     var self = this;
     this.set("isWorkflowImporting", true);
-    this.set("workflowFilePath", filePath);
     this.resetDesigner();
     //this.set("isWorkflowImporting", true);
     var workflowXmlDefered=this.getWorkflowFromHdfs(filePath);
     workflowXmlDefered.promise.then(function(data){
       this.importWorkflowFromString(data);
       this.set("isWorkflowImporting", false);
+      this.set("workflowFilePath", filePath);
     }.bind(this)).catch(function(data){
       console.error(data);
       var stackTraceMsg = self.getStackTrace(data.responseText);
@@ -636,7 +636,7 @@ export default Ember.Component.extend(FindNodeMixin, 
Validations, {
       this.set('errors',this.get('workflowContext').getErrors());
     }else{
       var dynamicProperties = 
this.get('propertyExtractor').getDynamicProperties(workflowXml);
-      var 
configForSubmit={props:dynamicProperties,xml:workflowXml,params:this.get('workflow.parameters')};
+      var configForSubmit={props:Array.from(dynamicProperties.values(), key => 
key),xml:workflowXml,params:this.get('workflow.parameters')};
       this.set("workflowSubmitConfigs",configForSubmit);
       this.set("showingWorkflowConfigProps",true);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js 
b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
index 8b685f0..0979c25 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
@@ -48,6 +48,11 @@ export default Ember.Component.extend(Validations, {
   alertDetails : "",
   filePath : "",
   showErrorMessage: false,
+  customProps : {
+    configuration : {
+      property : Ember.A([])
+    }
+  },
   displayName : Ember.computed('type', function(){
     if(this.get('type') === 'wf'){
       return "Workflow";
@@ -57,26 +62,34 @@ export default Ember.Component.extend(Validations, {
       return "Bundle";
     }
   }),
-  initialize :function(){
-    this.set("configPropsExists", this.get("jobConfigs").props.size>0);
+  jobProps : Ember.computed.alias('jobConfigs.props'),
+  configPropsExists : Ember.computed('jobProps.[]', function(){
+    return this.get("jobProps").length > 0;
+  }),
+  configMap : Ember.computed('jobProps.[]', function(){
     var configProperties = [];
     configProperties.pushObjects(this.extractJobParams());
     configProperties.pushObjects(this.extractJobProperties());
+    return configProperties;
+  }),
+  initialize :function(){
     this.configureExecutionSettings();
-    this.set("configMap", configProperties);
     this.set("jobXml", this.get("jobConfigs").xml);
     this.set('filePath', Ember.copy(this.get('jobFilePath')));
     Object.keys(this.get('validations.attrs')).forEach((attr)=>{
-    var field = 'validations.attrs.'+attr+'.isDirty';
-    this.set(field, false);
+      var field = 'validations.attrs.'+ attr +'.isDirty';
+      this.set(field, false);
     }, this);
   }.on('init'),
   rendered : function(){
     this.$("#configureJob").on('hidden.bs.modal', function () {
       this.sendAction('closeJobConfigs');
     }.bind(this));
-    this.$("#configureJob").modal("show");    
+    this.$("#configureJob").modal("show");
   }.on('didInsertElement'),
+  onDestroy : function(){
+    this.$("#configureJob").modal("hide");
+  }.on('willDestroyElement'),
   extractJobParams(){
     var params = [];
     var jobParams = this.get("jobConfigs").params;
@@ -98,7 +111,7 @@ export default Ember.Component.extend(Validations, {
   extractJobProperties(){
     var jobProperties = [];
     var jobParams = this.get("jobConfigs").params;
-    this.get("jobConfigs").props.forEach(function(value) {
+    this.get("jobProps").forEach(function(value) {
       if (value!== Constants.defaultNameNodeValue && 
value!==Constants.rmDefaultValue){
         var propName = value.trim().substring(2, value.length-1);
         var isRequired = true;
@@ -159,9 +172,14 @@ export default Ember.Component.extend(Validations, {
     var submitConfigs = this.get("configMap");
     submitConfigs.forEach(function(item) {
       url = url + "&config." + item.name + "=" + item.value;
-    }, this); 
+    }, this);
+    if(this.get('customProps.configuration.property')){
+      this.get('customProps.configuration.property').forEach(function(item) {
+        url = url + "&config." + item.name + "=" + item.value;
+      }, this);
+    }
     this.get('systemConfigs').forEach((config)=>{
-      if(config.name === 'runOnSubmit' && !isDryrun){
+      if(config.name === 'runOnSubmit' && config.value && !isDryrun){
         url = url + "&oozieparam.action=start";
       }else if(config.name !== 'runOnSubmit'){
         url = url + "&oozieconfig." + config.name + "=" + config.value;
@@ -170,7 +188,7 @@ export default Ember.Component.extend(Validations, {
     if(isDryrun){
       url = url + "&oozieparam.action=dryrun";
     }
-    if ( this.get("jobConfigs").props.has("${resourceManager}")){
+    if (this.get("jobProps").indexOf("${resourceManager}") >= 0){
       url= url + "&resourceManager=useDefault";
     }
     this.set("savingInProgress", true);
@@ -268,12 +286,13 @@ export default Ember.Component.extend(Validations, {
         detail=jsonResp.message;
       }
     }else{
-      detail=response; 
+      detail=response;
     }
     return detail;
   },
   actions: {
-    selectFile(){
+    selectFile(property){
+      this.set('fileModel', property);
       this.set("showingFileBrowser",true);
     },
     showStackTrace(){
@@ -284,6 +303,8 @@ export default Ember.Component.extend(Validations, {
     },
     closeFileBrowser(){
       this.set("showingFileBrowser",false);
+      
this.$(`input[name=${this.get('fileModel')}]`).val(this.get('selectedPath'))
+      this.$(`input[name=${this.get('fileModel')}]`).trigger('change');
     },
     dryrun(){
       this.set('showErrorMessage', true);
@@ -291,6 +312,7 @@ export default Ember.Component.extend(Validations, {
     },
     save(){
       this.set('showErrorMessage', true);
+      this.get('nameValueContext').trigger('bindInputPlaceholder');
       this.prepareJobForSubmission(false);
     },
     previewXml(){
@@ -298,6 +320,15 @@ export default Ember.Component.extend(Validations, {
     },
     closePreview(){
       this.set("showingPreview",false);
+    },
+    next(){
+      this.sendAction("extractProperties", 
this.get('parameterizedWorkflowPath'));
+    },
+    skip(){
+      this.set('containsParameteriedPaths', false);
+    },
+    register(context){
+      this.set('nameValueContext', context);
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/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
index 0ebd9a7..87cccae 100644
--- 
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
@@ -25,6 +25,10 @@ export default Ember.Service.extend({
   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,
+  containsParameters(path) {
+    var matches = path.match(this.get('extractor'));
+    return matches !== null;
+  },
   extract : function(property) {
     var matches = property.match(this.get('extractor'));
     var dynamicProperties = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
 
b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
index 5b5cd68..7ee7ecd 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
@@ -315,7 +315,11 @@
 {{hdfs-browser closeFileBrowser="closeFileBrowser" 
selectFileCallback=selectFileCallback filePath=filePath}}
 {{/if}}
 {{#if showingJobConfig}}
-{{job-config type='coord' closeJobConfigs="closeCoordSubmitConfig" 
jobFilePath=coordinatorFilePath openFileBrowser="openFileBrowser" 
closeFileBrowser="closeFileBrowser" jobConfigs=coordinatorConfigs}}
+  {{job-config type='coord' closeJobConfigs="closeCoordSubmitConfig"
+    parameterizedWorkflowPath=parameterizedWorkflowPath
+    extractProperties="extractProperties" 
containsParameteriedPaths=containsParameteriedPaths
+    jobFilePath=coordinatorFilePath openFileBrowser="openFileBrowser"
+    closeFileBrowser="closeFileBrowser" jobConfigs=coordinatorConfigs}}
 {{/if}}
 {{#if showingResetConfirmation}}
 {{#confirmation-dialog title="Confirm Coordinator Reset"

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6affb41/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
 
b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
index f0d9ee3..b33420a 100644
--- 
a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
+++ 
b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
@@ -25,9 +25,56 @@
         {{else}}
           <h4 class="modal-title">Submit {{displayName}}</h4>
         {{/if}}
-
       </div>
       <div class="modal-body">
+        {{designer-errors errors=jobConfigs.errors}}
+        {{#if (and (eq type 'bundle') containsParameteriedPaths)}}
+        <div class="panel panel-default">
+          <div class="panel-body">
+            <div class="col-xs-24">
+              <span>The underlying workflow path is templatized.
+                 Please enter the workflow path to deduce the templatized 
properties in the workflow.
+               </span>
+            </div>
+            {{#each parameterizedPaths as |path index|}}
+            <div class="row form-group">
+              <div class="col-xs-3">
+                <label class="control-label" for="path">Workflow 
path</label><span class="requiredField">&nbsp;*</span>
+              </div>
+              <div class="col-xs-8">
+                <div class="input-group">
+                  {{input class="form-control" type="text" name=path.name 
value=path.value}}
+                  <span class="input-group-btn">
+                    <button type="button" class="btn btn-primary" {{action 
"selectFile" path.name}}>Browse</button>
+                  </span>
+                </div>
+                {{field-error model=this field='filePath' 
showErrorMessage=showErrorMessage}}
+              </div>
+            </div>
+            {{/each}}
+          </div>
+        </div>
+        {{else if (and (eq type 'coord') containsParameteriedPaths)}}
+        <div class="col-xs-24">
+          <div class="alert alert-warning" role="alert">
+            Workflow path contains variables. Please provide the absolute path 
to auto detect templatized variables. Skip this step if you have configured all 
the templatized varibales of the workflow in the coordinator.
+          </div>
+        </div>
+        <div class="row form-group">
+          <div class="col-xs-3">
+            <label class="control-label" for="path">Workflow path</label><span 
class="requiredField">&nbsp;*</span>
+          </div>
+          <div class="col-xs-8">
+            <div class="input-group">
+              {{input class="form-control" type="text" name='wfPath' 
value=parameterizedWorkflowPath}}
+              <span class="input-group-btn">
+                <button type="button" class="btn btn-primary" {{action 
"selectFile" 'wfPath'}}>Browse</button>
+              </span>
+            </div>
+            {{field-error model=this field='filePath' 
showErrorMessage=showErrorMessage}}
+          </div>
+        </div>
+        {{else}}
         <div class="panel panel-default">
           <div class="panel-body">
             {{#if alertType}}
@@ -51,9 +98,9 @@
               </div>
               <div class="col-xs-8">
                 <div class="input-group">
-                  {{input class="form-control" type="text" 
name="{{type}}-path"  value=filePath}}
+                  {{input class="form-control" name="filePath" type="text" 
value=filePath}}
                   <span class="input-group-btn">
-                    <button type="button" class="btn btn-primary" {{action 
"selectFile"}}>Browse</button>
+                    <button type="button" class="btn btn-primary" {{action 
"selectFile" "filePath"}}>Browse</button>
                   </span>
                 </div>
                 {{field-error model=this field='filePath' 
showErrorMessage=showErrorMessage}}
@@ -76,51 +123,65 @@
         </div>
         <div id="jobProperties">
           {{#if configMap.length}}
-          <div class="panel panel-default">
-            <div class="panel-heading">
-              Job Properties
-            </div>
-            <div class="panel-body">
-              {{field-error model=this field='configMap' 
showErrorMessage=showErrorMessage}}
-              {{#each configMap as |prop|}}
-              <div class="row form-group">
-                <div class="col-xs-3">
-                  <label class="control-label" 
for="{{prop}}">{{prop.name}}</label>
-                  {{#if prop.isRequired}}
-                  <span class="requiredField">&nbsp;*</span>
-                  {{/if}}
-                </div>
-                <div class="col-xs-8">
-                  {{input class="form-control" type="text" value=prop.value}}
-                </div>
+            <div class="panel panel-default">
+              <div class="panel-heading">
+                Job Properties
+              </div>
+              <div class="panel-body">
+                {{field-error model=this field='configMap' 
showErrorMessage=showErrorMessage}}
+                {{#each configMap as |prop index|}}
+                  <div class="row form-group">
+                    <div class="col-xs-3">
+                      <label class="control-label" 
for="{{prop}}">{{prop.name}}</label>
+                      {{#if prop.isRequired}}
+                        <span class="requiredField">&nbsp;*</span>
+                      {{/if}}
+                    </div>
+                    <div class="col-xs-8">
+                      {{input class="form-control" type="text" 
value=prop.value}}
+                    </div>
+                  </div>
+                {{/each}}
               </div>
-              {{/each}}
             </div>
-          </div>
           {{/if}}
+          <div class=" panel panel-default">
+            <div class="panel-heading">Custom Job Properties</div>
+            <div class="panel-body handlerPanel">
+              <form class="form-horizontal">
+                {{#name-value-config configuration=customProps.configuration 
register="register"}}{{/name-value-config}}
+              </form>
+            </div>
+          </div>
         </div>
+        {{/if}}
+
       </div>
       <div class="modal-footer">
-        {{#if savingInProgress}}
-        {{spin-spinner lines=10 length=10 width=5 radius=10 }}
-        <span class="pull-left">Saving {{displayName}}</span>
-        {{/if}}
-        {{#if startingInProgress}}
-        {{spin-spinner lines=8 length=5 width=10 radius=5}}
-        <span class="pull-left">Starting {{displayName}}</span>
-        {{/if}}
-        <button type="button" class="btn btn-default" 
data-dismiss="modal">Close</button>
-        {{#if isDryrun}}
-          <button type="button" class="btn btn-primary" {{action 
"dryrun"}}>Validate</button>
+        {{#if containsParameteriedPaths}}
+          <button type="button" class="btn btn-default" {{action 
"skip"}}>Skip</button>
+          <button type="button" class="btn btn-primary" {{action 
"next"}}>Next</button>
         {{else}}
-          <button type="button" class="btn btn-default" {{action 
"dryrun"}}>Validate</button>
-          <button type="button" class="btn btn-primary" {{action 
"save"}}>Submit</button>
+          {{#if savingInProgress}}
+            {{spin-spinner lines=10 length=10 width=5 radius=10 }}
+            <span class="pull-left">Saving {{displayName}}</span>
+            {{/if}}
+          {{#if startingInProgress}}
+            {{spin-spinner lines=8 length=5 width=10 radius=5}}
+            <span class="pull-left">Starting {{displayName}}</span>
+          {{/if}}
+          <button type="button" class="btn btn-default" 
data-dismiss="modal">Close</button>
+          {{#if isDryrun}}
+            <button type="button" class="btn btn-primary" {{action 
"dryrun"}}>Validate</button>
+          {{else}}
+            <button type="button" class="btn btn-default" {{action 
"dryrun"}}>Validate</button>
+            <button type="button" class="btn btn-primary" {{action 
"save"}}>Submit</button>
+          {{/if}}
         {{/if}}
-
       </div>
     </div>
   </div>
 </div>
 {{#if showingFileBrowser}}
-{{hdfs-browser closeFileBrowser="closeFileBrowser" 
selectFileCallback=selectFileCallback filePath=filePath}}
+{{hdfs-browser closeFileBrowser="closeFileBrowser" 
selectFileCallback=selectFileCallback filePath=selectedPath}}
 {{/if}}

Reply via email to