Repository: ambari
Updated Branches:
  refs/heads/trunk e74bfa4a4 -> 9bef76ba0


AMBARI-15979 Provide UI validation for widget_name and description fields in 
Create/Edit Widget pop-up. (Keta Patel via atkach)


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

Branch: refs/heads/trunk
Commit: 9bef76ba08fe190ad40d128cf317dce0df36f7f4
Parents: e74bfa4
Author: Andrii Tkach <[email protected]>
Authored: Thu Apr 28 11:53:07 2016 +0300
Committer: Andrii Tkach <[email protected]>
Committed: Thu Apr 28 11:53:07 2016 +0300

----------------------------------------------------------------------
 .../service/widgets/create/step3_controller.js  | 58 +++++++++++-
 ambari-web/app/messages.js                      |  2 +
 .../main/service/widgets/create/step3.hbs       |  6 +-
 ambari-web/app/utils/validator.js               | 20 +++++
 .../widgets/create/step3_controller_test.js     | 92 +++++++++++++++++++-
 5 files changed, 169 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9bef76ba/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js 
b/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
index dd7a93f..eebe1f5 100644
--- a/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
@@ -18,6 +18,8 @@
 
 var App = require('app');
 
+var validator = require('utils/validator');
+
 App.WidgetWizardStep3Controller = Em.Controller.extend({
   name: "widgetWizardStep3Controller",
 
@@ -29,11 +31,26 @@ App.WidgetWizardStep3Controller = Em.Controller.extend({
   widgetName: '',
 
   /**
+   * @type {boolean}
+   */
+  isNameInvalid: false,
+
+  /**
    * @type {string}
    */
   widgetAuthor: '',
 
   /**
+   * @type {string}
+   */
+  widgetNameErrorMessage: '',
+
+  /**
+   * @type {string}
+   */
+  descriptionErrorMessage: '',
+
+  /**
    * @type {boolean}
    */
   isSharedChecked: false,
@@ -54,6 +71,11 @@ App.WidgetWizardStep3Controller = Em.Controller.extend({
   widgetDescription: '',
 
   /**
+   * @type {boolean}
+   */
+  isDescriptionInvalid: false,
+
+  /**
    * actual values of properties in API format
    * @type {object}
    */
@@ -82,14 +104,42 @@ App.WidgetWizardStep3Controller = Em.Controller.extend({
   isSubmitDisabled: Em.computed.or('widgetNameEmpty', 'isNameInvalid', 
'isDescriptionInvalid'),
 
   /**
-   * @type {boolean}
+   * validates the name on 3rd step
    */
-  isNameInvalid: Em.computed.gte('widgetName.length', 129),
+  validateName: function(){
+    var errorMessage='';
+    var widgetName = this.get('widgetName');
+    this.set("isNameInvalid",false);
+    if(widgetName && widgetName.length > 128){
+      errorMessage = Em.I18n.t("widget.create.wizard.step3.name.invalid.msg");
+      this.set("isNameInvalid",true);
+    }
+
+    if(widgetName && !validator.isValidWidgetName(widgetName)){
+      errorMessage = 
Em.I18n.t("widget.create.wizard.step3.name.invalidCharacter.msg");
+      this.set("isNameInvalid",true);
+    }
+    this.set('widgetNameErrorMessage',errorMessage);
+  }.observes('widgetName'),
 
   /**
-   * @type {boolean}
+   * validates the description on 3rd step
    */
-  isDescriptionInvalid: Em.computed.gte('widgetDescription.length', 2049),
+  validateDescription: function(){
+    var errorMessage='';
+    var widgetDescription = this.get('widgetDescription');
+    this.set("isDescriptionInvalid",false);
+    if(widgetDescription && widgetDescription.length > 2048){
+      errorMessage = 
Em.I18n.t("widget.create.wizard.step3.description.invalid.msg");
+      this.set("isDescriptionInvalid",true);
+    }
+
+    if(widgetDescription && 
!validator.isValidWidgetDescription(widgetDescription)){
+      errorMessage = 
Em.I18n.t("widget.create.wizard.step3.description.invalidCharacter.msg");
+      this.set("isDescriptionInvalid",true);
+    }
+    this.set('descriptionErrorMessage',errorMessage);
+  }.observes('widgetDescription'),
 
   /**
    * restore widget data set on 2nd step

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bef76ba/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 8c8b9e5..eea0e2a 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2844,7 +2844,9 @@ Em.I18n.translations = {
   'widget.create.wizard.step3.sharing.msg': 'Share this widget in the widget 
library',
   'widget.create.wizard.step3.header': 'Name and Description',
   'widget.create.wizard.step3.name.invalid.msg': 'Widget name is too long. 
Please enter a widget name less than 129 characters.',
+  'widget.create.wizard.step3.name.invalidCharacter.msg': 'Invalid widget 
name. Only alphanumerics, underscores, hyphens, percentage and spaces are 
allowed.',
   'widget.create.wizard.step3.description.invalid.msg': 'Description is too 
long. Please enter a description less than 2049 characters.',
+  'widget.create.wizard.step3.description.invalidCharacter.msg': 'Invalid 
input. Only alphanumerics, underscores, hyphens, percentage and spaces are 
allowed.',
 
   'widget.edit.wizard.header': 'Edit Widget',
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bef76ba/ambari-web/app/templates/main/service/widgets/create/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/widgets/create/step3.hbs 
b/ambari-web/app/templates/main/service/widgets/create/step3.hbs
index 9f431af..81177bc 100644
--- a/ambari-web/app/templates/main/service/widgets/create/step3.hbs
+++ b/ambari-web/app/templates/main/service/widgets/create/step3.hbs
@@ -25,7 +25,7 @@
       <div {{bindAttr class=":span10 isNameInvalid:error"}}>
         {{view Ember.TextField valueBinding="widgetName"}}
         {{#if isNameInvalid}}
-          <div>{{t widget.create.wizard.step3.name.invalid.msg}}</div>
+          <div>{{widgetNameErrorMessage}}</div>
         {{/if}}
       </div>
     </div>
@@ -50,7 +50,7 @@
       <div {{bindAttr class=":span10 isDescriptionInvalid:error"}}>
         {{view Ember.TextArea valueBinding="widgetDescription" 
class="description-text-area"}}
         {{#if isDescriptionInvalid}}
-          <div>{{t widget.create.wizard.step3.description.invalid.msg}}</div>
+          <div>{{descriptionErrorMessage}}</div>
         {{/if}}
       </div>
     </div>
@@ -62,4 +62,4 @@
     <button id="add-widget-step3-save" class="btn btn-success pull-right" 
{{bindAttr disabled="isSubmitDisabled"}} {{action "complete" 
target="controller"}}>{{t common.save}}</button>
     <button id="add-widget-step3-cancel" class="btn pull-right" {{action 
"cancel" target="controller"}}>{{t common.cancel}}</button>
   </div>
-</div>
\ No newline at end of file
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bef76ba/ambari-web/app/utils/validator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/validator.js 
b/ambari-web/app/utils/validator.js
index 490fec5..896228b 100644
--- a/ambari-web/app/utils/validator.js
+++ b/ambari-web/app/utils/validator.js
@@ -292,5 +292,25 @@ module.exports = {
     var remotePattern = 
/^(?:(?:https?|ftp):\/{2})(?:\S+(?::\S*)?@)?(?:(?:(?:[\w\-.]))*)(?::[0-9]+)?(?:\/\S*)?$/,
       localPattern = 
/^file:\/{2,3}([a-zA-Z][:|]\/){0,1}[\w~!*'();@&=\/\\\-+$,?%#.\[\]]+$/;
     return remotePattern.test(value) || localPattern.test(value);
+  },
+
+  /**
+   * Validate widget name
+   * @param {string} value
+   * @returns {boolean}
+   */
+  isValidWidgetName: function(value) {
+    var widgetNameRegex = /^[\s0-9a-z_\-%]+$/i;
+    return widgetNameRegex.test(value);
+  },
+
+  /**
+   * Validate widget description
+   * @param {string} value
+   * @returns {boolean}
+   */
+  isValidWidgetDescription: function(value) {
+    var widgetDescriptionRegex = /^[\s0-9a-z_\-%]+$/i;
+    return widgetDescriptionRegex.test(value);
   }
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/9bef76ba/ambari-web/test/controllers/main/service/widgets/create/step3_controller_test.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/test/controllers/main/service/widgets/create/step3_controller_test.js
 
b/ambari-web/test/controllers/main/service/widgets/create/step3_controller_test.js
index 6f92142..d54d04a 100644
--- 
a/ambari-web/test/controllers/main/service/widgets/create/step3_controller_test.js
+++ 
b/ambari-web/test/controllers/main/service/widgets/create/step3_controller_test.js
@@ -30,12 +30,100 @@ describe('App.WidgetWizardStep3Controller', function () {
 
   App.TestAliases.testAsComputedIfThenElse(controller, 'widgetScope', 
'isSharedChecked', 'Cluster', 'User');
 
-  App.TestAliases.testAsComputedGte(controller, 'isNameInvalid', 
'widgetName.length', 129);
+  //App.TestAliases.testAsComputedGte(controller, 'isNameInvalid', 
'widgetName.length', 129);
 
-  App.TestAliases.testAsComputedGte(controller, 'isDescriptionInvalid', 
'widgetDescription.length', 2049);
+  //App.TestAliases.testAsComputedGte(controller, 'isDescriptionInvalid', 
'widgetDescription.length', 2049);
 
   App.TestAliases.testAsComputedOr(controller, 'isSubmitDisabled', 
['widgetNameEmpty', 'isNameInvalid', 'isDescriptionInvalid']);
 
+  describe("#validateName", function(){
+    var testCases = [
+      {
+        widgetName: 'abc 123 _ - %',
+        result: {
+          errorMessage: '',
+          isNameInvalid: false
+        }
+      },
+      {
+        widgetName: '$#@!',
+        result: {
+          errorMessage: 
Em.I18n.t('widget.create.wizard.step3.name.invalidCharacter.msg'),
+          isNameInvalid: true
+        }
+      },
+      {
+        widgetName: 
'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789',
+        result: {
+          errorMessage: 
Em.I18n.t('widget.create.wizard.step3.name.invalid.msg'),
+          isNameInvalid: true
+        },
+      },
+      {
+        widgetName: '',
+        result: {
+          errorMessage: '',
+          isNameInvalid: false
+        }
+      }
+    ];
+
+    testCases.forEach(function(test){
+      controller.setProperties({
+        widgetName: test.widgetName
+      });
+
+      //Since validateName() observes the property "widgetName", Ember 
framework will call it
+
+      
expect(controller.get('widgetNameErrorMessage')).to.equal(test.result.errorMessage);
+      
expect(controller.get('isNameInvalid')).to.equal(test.result.isNameInvalid);
+    });
+  });
+
+  describe("#validateDescription", function(){
+    var testCases = [
+      {
+        widgetDescription: 'abc 123 _ - %',
+        result: {
+          errorMessage: '',
+          isDescriptionInvalid: false
+        }
+      },
+      {
+        widgetDescription: '$#@!',
+        result: {
+          errorMessage: 
Em.I18n.t('widget.create.wizard.step3.description.invalidCharacter.msg'),
+          isDescriptionInvalid: true
+        }
+      },
+      {
+        widgetDescription: 
'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
 
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
 
78901234567890123456789012345678901234567890123456789012345678901234567890123456789',
+        result: {
+          errorMessage: 
Em.I18n.t('widget.create.wizard.step3.description.invalid.msg'),
+          isDescriptionInvalid: true
+        }
+      },
+      {
+        widgetDescription: '',
+        result: {
+          errorMessage: '',
+          isDescriptionInvalid: false
+        }
+      }
+    ];
+
+    testCases.forEach(function(test){
+      controller.setProperties({
+        widgetDescription: test.widgetDescription
+      });
+
+      //Since validateDescription() observes the property "widgetDescription", 
Ember framework will call it
+
+      
expect(controller.get('descriptionErrorMessage')).to.equal(test.result.errorMessage);
+      
expect(controller.get('isDescriptionInvalid')).to.equal(test.result.isDescriptionInvalid);
+    });
+  });
+
   describe("#initPreviewData()", function () {
     beforeEach(function () {
       sinon.stub(controller, 'addObserver');

Reply via email to