AMBARI-20206.Workflow manager is allowing to have empty action node.(Padma Priya N via gauravn7)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/99df82fa Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/99df82fa Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/99df82fa Branch: refs/heads/branch-feature-AMBARI-12556 Commit: 99df82fa47df7a7bc55dead563943071adf37a48 Parents: 0e3ced1 Author: Gaurav Nagar <[email protected]> Authored: Wed Mar 1 17:19:11 2017 +0530 Committer: Gaurav Nagar <[email protected]> Committed: Wed Mar 1 17:19:56 2017 +0530 ---------------------------------------------------------------------- .../ui/app/components/flow-designer.js | 37 ++++++++++++++------ .../src/main/resources/ui/app/routes/index.js | 7 ++++ .../templates/components/designer-errors.hbs | 2 +- .../main/resources/ui/app/templates/index.hbs | 5 ++- .../app/validators/duplicate-data-node-name.js | 20 +++++------ .../app/validators/duplicate-kill-node-name.js | 28 ++++++--------- 6 files changed, 59 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/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 2d326d1..2f8455f 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 @@ -44,13 +44,6 @@ const Validations = buildValidations({ dependentKeys: ['[email protected]'] }) ] - }, - 'flattenedNodes': { - validators: [ - validator('duplicate-flattened-node-name', { - dependentKeys: ['[email protected]'] - }) - ] } }); @@ -88,7 +81,23 @@ export default Ember.Component.extend(FindNodeMixin, Validations, { parameters : {}, clonedDomain : {}, clonedErrorNode : {}, - validationErrors : [], + validationErrors : Ember.computed('validations.attrs.dataNodes.message', 'validations.attrs.workflow.killNodes.message', { + get(key){ + var errors = []; + if(this.get('validations.attrs.dataNodes.message')){ + errors.pushObject({message : this.get('validations.attrs.dataNodes.message')}); + } + if(this.get('validations.attrs.workflow.killNodes.message')){ + errors.pushObject(this.get('validations.attrs.dataNodes.message')); + } + return errors; + }, + set(key, value){ + if(!value){ + this.set(key, Ember.A([])); + } + } + }), showingFileBrowser : false, killNode : {}, isWorkflowImporting: false, @@ -112,6 +121,8 @@ export default Ember.Component.extend(FindNodeMixin, Validations, { this.set('flowRenderer',CytoscapeRenderer.create()); this.set('workflow',Workflow.create({})); CommonUtils.setTestContext(this); + this.set('dataNodes', Ember.A([])); + this.set('validationErrors', Ember.A([])); }.on('init'), elementsInserted :function(){ this.setConentWidth(); @@ -830,9 +841,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, { createKillNode(killNode){ this.set("killNode", killNode); this.set("createKillnodeError",null); - var existingKillNode=this.get('workflow').get("killNodes").findBy("name",this.get('killNode.name')); + var existingKillNode= this.get('workflow').get("killNodes").findBy("name",this.get('killNode.name')) || this.get('dataNodes').findBy("dataNodeName", this.get('killNode.name')); if (existingKillNode){ - this.set("createKillnodeError","The kill node already exists"); + this.set("createKillnodeError","Node with same name already exists"); return; } if (Ember.isBlank(this.get('killNode.name'))){ @@ -919,6 +930,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, { }, this); }, submitWorkflow(){ + if(this.get('validationErrors') && this.get('validationErrors').length > 0){ + return; + } this.set('dryrun', false); this.openJobConfig(); }, @@ -926,6 +940,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, { this.openSaveWorkflow(); }, previewWorkflow(){ + if(this.get('validationErrors') && this.get('validationErrors').length > 0){ + return; + } this.set("showingPreview",false); this.get('workflowContext').clearErrors(); var workflowGenerator=WorkflowGenerator.create({workflow:this.get("workflow"), http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/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 index 8aac32b..316ec0e 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/index.js @@ -43,6 +43,8 @@ export default Ember.Route.extend({ }).catch((e)=>{ console.error(e); Ember.set(serviceCheck, 'isAvailable', false); + var response = typeof e.responseText === "string"? JSON.parse(e.responseText) : e.responseText; + Ember.set(serviceCheck, 'stackTrace', response.stackTrace); }).finally(()=>{ Ember.set(serviceCheck, 'checkCompleted', true); }); @@ -106,5 +108,10 @@ export default Ember.Route.extend({ } }); }); + }, + actions : { + showDetails (check){ + Ember.set(check, 'showingDetails', !check.showingDetails); + } } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-errors.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-errors.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-errors.hbs index 00cb8a6..3cab194 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-errors.hbs +++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-errors.hbs @@ -29,7 +29,7 @@ {{/if}} {{#if (gt validationErrors.length 0)}} {{#each validationErrors as |error|}} - <div>{{error.node.name}} : {{error.message}}</div> + <div>{{error.node.name}} {{#if error.node}}:{{/if}} {{error.message}}</div> {{/each}} {{/if}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/contrib/views/wfmanager/src/main/resources/ui/app/templates/index.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/index.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/index.hbs index d96be85..bb82df8 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/index.hbs +++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/index.hbs @@ -59,7 +59,10 @@ <h3>Issues detected</h3> {{#each serviceChecks as |check|}} {{#if (and (not check.isAvailable) check.checkCompleted)}} - {{check.errorMessage}} <br> + {{check.errorMessage}} <a class="pointer action-link" href="javascript:void(0)" {{action "showDetails" check}}>Details</a><br> + {{#if check.showingDetails}} + <div class="well">{{check.stackTrace}}</div> + {{/if}} {{/if}} {{/each}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js index 86e5182..7336d6e 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js @@ -20,23 +20,23 @@ import BaseValidator from 'ember-cp-validations/validators/base'; const DuplicateDataNodeName = BaseValidator.extend({ validate(value, options, model, attribute) { if (model.get('dataNodes')) { - var nodeNames = new Map(); - model.get("validationErrors").clear(); - model.get('dataNodes').forEach((item)=>{ - if (item.data.node && item.data.node.name) { + var killNodes = model.get('workflow').killNodes || []; + var nodeNames = new Map(killNodes.map((killNode) => [killNode.name, killNode.name])); + for(let i=0;i<model.get('dataNodes').length;i++){ + let item = model.get('dataNodes').objectAt(i); + if (item.data.node) { + if(Ember.isBlank(item.data.node.name)){ + return "Node name should not be blank"; + } Ember.set(item.data.node, "errors", false); - if(nodeNames.get(item.data.node.name) && item.data.node.type!=='kill'){ + if(nodeNames.get(item.data.node.name)){ Ember.set(item.data.node, "errors", true); - model.get("validationErrors").pushObject({node:item.data,message:"Node name should be unique"}); + return `${item.data.node.name} : Node name should be unique`; }else{ nodeNames.set(item.data.node.name, item.data); Ember.set(item.data.node, "errors", false); } } - }); - - if(model.get('dataNodes').length !== nodeNames.size){ - return false; } return true; } http://git-wip-us.apache.org/repos/asf/ambari/blob/99df82fa/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js index b8770c2..cc764b9 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js @@ -18,27 +18,19 @@ import BaseValidator from 'ember-cp-validations/validators/base'; const DuplicateKillNodeName = BaseValidator.extend({ validate(value, options, model, attribute) { - let killNodes = [], flag; - model.get("validationErrors").clear(); - if(model.get("workflow") && model.get("workflow").killNodes){ - killNodes = model.get("workflow").killNodes; - for(let i=0; i<killNodes.length; i++){ - for(let j=0; j<killNodes.length; j++){ - if(killNodes[i].name === killNodes[j].name && i !== j){ - model.get('validationErrors').pushObject({node : killNodes[j] ,message : "Duplicate killnode"}); - flag = true; - break; + if (model.get("workflow") && model.get("workflow").killNodes) { + var dataNodes = model.get('dataNodes') || []; + var nodeNames = new Map(dataNodes.map((node) => [node.name, node.name])); + for(let i = 0; i < model.get("workflow").killNodes.length; i++){ + let item = model.get("workflow").killNodes.objectAt(i); + if(nodeNames.get(item.name)){ + return `${item.name} : Node name should be unique`; + }else{ + nodeNames.set(item.name, item); } } - if(flag){ - break; - } - } - } - if (flag){ - return false; + return true; } - return true; } });
