You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ak...@apache.org on 2014/05/21 19:13:59 UTC

git commit: AMBARI-5844. Provide 'Create App' Wizard Step1 functionallity. (akovalenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk d4f502272 -> d4afecaf0


AMBARI-5844. Provide 'Create App' Wizard Step1 functionallity. (akovalenko)


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

Branch: refs/heads/trunk
Commit: d4afecaf06e642c96ecf7d55eb228e845fbbfd29
Parents: d4f5022
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Wed May 21 20:12:05 2014 +0300
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Wed May 21 20:12:05 2014 +0300

----------------------------------------------------------------------
 .../ui/app/controllers/createAppWizard/step1.js | 142 +++++++++++++++++++
 .../main/resources/ui/app/models/slider_app.js  |  11 +-
 .../ui/app/models/slider_app_component.js       |   2 +-
 .../resources/ui/app/models/slider_app_type.js  |   2 +-
 .../ui/app/templates/createAppWizard/step1.hbs  |  19 ++-
 .../src/main/resources/ui/app/translations.js   |   9 +-
 .../ui/app/views/createAppWizard/step1.js       |  43 ++++++
 7 files changed, 214 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1.js b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1.js
new file mode 100644
index 0000000..d162db5
--- /dev/null
+++ b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1.js
@@ -0,0 +1,142 @@
+/**
+ * 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.
+ */
+
+App.CreateAppWizardStep1Controller = Ember.Controller.extend({
+
+  needs: "createAppWizard",
+
+  appWizardController: Ember.computed.alias("controllers.createAppWizard"),
+
+  /**
+   * New App object
+   * @type {App.SliderApp}
+   */
+  newApp: null,
+
+  /**
+   * Name for new App
+   * @type {String}
+   */
+  newAppName: '',
+
+  /**
+   * List of available types for App
+   * @type {Array}
+   */
+  availableTypes: [],
+
+  /**
+   * Selected type for new App
+   * @type {App.SliderAppType}
+   */
+  selectedType: null,
+
+  /**
+   * Define if <code>newAppName</code> pass validation
+   * @type {Boolean}
+   */
+  isNameError: false,
+
+  /**
+   * Error message describing App name validation error
+   * @type {String}
+   */
+  nameErrorMessage: '',
+
+  /**
+   * Load all required data for step
+   */
+  loadStep: function () {
+    this.initializeNewApp();
+    this.loadAvailableTypes();
+  },
+
+  /**
+   * Initialize new App and set it to <code>newApp</code>
+   */
+  initializeNewApp: function () {
+    // find early initialized app
+    var newApp = this.store.all('sliderApp').findBy('status', App.SliderApp.Status.initialized);
+    // if there is no one, than create new one
+    if (!newApp) {
+      newApp = this.store.push('sliderApp', {status: App.SliderApp.Status.initialized, id: 'app' + (new Date).getTime()});
+    }
+    this.set('newApp', newApp);
+  },
+
+  /**
+   * Load all available types for App
+   */
+  loadAvailableTypes: function () {
+    this.set('availableTypes', this.store.all('sliderAppType'));
+  },
+
+  /**
+   * Validate <code>newAppName</code>
+   * It should consist only of letters, numbers, '-', '_' and first character should be a letter
+   * @return {Boolean}
+   */
+  nameValidator: function () {
+    var newAppName = this.get('newAppName');
+    if (newAppName) {
+      // new App name should consist only of letters, numbers, '-', '_' and first character should be a letter
+      if (!/^[A-Za-z][A-Za-z0-9_\-]*$/.test(newAppName)) {
+        this.set('isNameError', true);
+        this.set('nameErrorMessage', Em.I18n.t('wizard.step1.nameFormatError'));
+        return false;
+      }
+      // new App name should be unique
+      if (this.store.all('sliderApp').mapProperty('name').contains(newAppName)) {
+        this.set('isNameError', true);
+        this.set('nameErrorMessage', Em.I18n.t('wizard.step1.nameRepeatError'));
+        return false;
+      }
+    }
+    this.set('isNameError', false);
+    return true;
+  }.observes('newAppName'),
+
+  /**
+   * Define description depending on selected App type
+   */
+  typeDescription: function () {
+    var selectedType = this.get('selectedType');
+    return selectedType ? Em.I18n.t('wizard.step1.typeDescription').format(selectedType.get('displayName')) : '';
+  }.property('selectedType'),
+
+  /**
+   * Define if submit button is disabled
+   * <code>newAppName</code> should pass validation and be not empty
+   */
+  isSubmitDisabled: function () {
+    return !this.get('newAppName') || this.get('isNameError');
+  }.property('newAppName', 'isNameError'),
+
+  saveApp: function () {
+    var newApp = this.get('newApp');
+    newApp.set('appType', this.get('selectedType'));
+    newApp.set('name', this.get('newAppName'));
+  },
+
+  actions: {
+    submit: function () {
+      this.saveApp();
+      this.get('appWizardController').nextStep();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/models/slider_app.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/models/slider_app.js b/contrib/views/slider/src/main/resources/ui/app/models/slider_app.js
index 022b35f..72e51ae 100644
--- a/contrib/views/slider/src/main/resources/ui/app/models/slider_app.js
+++ b/contrib/views/slider/src/main/resources/ui/app/models/slider_app.js
@@ -56,7 +56,7 @@ App.SliderApp = DS.Model.extend({
   /**
    * @type {App.SliderAppType}
    */
-  appType: DS.belongsTo('SliderAppType'),
+  appType: DS.belongsTo('sliderAppType'),
 
   /**
    * @type {string}
@@ -66,17 +66,17 @@ App.SliderApp = DS.Model.extend({
   /**
    * @type {App.SliderAppComponent[]}
    */
-  components: DS.hasMany('SliderAppComponent'),
+  components: DS.hasMany('sliderAppComponent'),
 
   /**
    * @type {App.QuickLink[]}
    */
-  quickLinks: DS.hasMany('QuickLink'),
+  quickLinks: DS.hasMany('quickLink'),
 
   /**
    * @type {App.TypedProperty[]}
    */
-  runtimeProperties: DS.hasMany('TypedProperty')
+  runtimeProperties: DS.hasMany('typedProperty')
 });
 
 App.SliderApp.FIXTURES = [
@@ -160,5 +160,6 @@ App.SliderApp.FIXTURES = [
 App.SliderApp.Status = {
   running: "Running",
   frozen: "Frozen",
-  destroyed: "Destroyed"
+  destroyed: "Destroyed",
+  initialized: "Initialized"
 };
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/models/slider_app_component.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/models/slider_app_component.js b/contrib/views/slider/src/main/resources/ui/app/models/slider_app_component.js
index e6602a6..2d70a13 100644
--- a/contrib/views/slider/src/main/resources/ui/app/models/slider_app_component.js
+++ b/contrib/views/slider/src/main/resources/ui/app/models/slider_app_component.js
@@ -31,7 +31,7 @@ App.SliderAppComponent = DS.Model.extend({
   /**
    * @type {App.Host}
    */
-  host: DS.belongsTo('Host')
+  host: DS.belongsTo('host')
 
 });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/models/slider_app_type.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/models/slider_app_type.js b/contrib/views/slider/src/main/resources/ui/app/models/slider_app_type.js
index 9b7f991..2888407 100644
--- a/contrib/views/slider/src/main/resources/ui/app/models/slider_app_type.js
+++ b/contrib/views/slider/src/main/resources/ui/app/models/slider_app_type.js
@@ -31,7 +31,7 @@ App.SliderAppType = DS.Model.extend({
   /**
    * @type {App.SliderAppTypeComponent[]}
    */
-  components: DS.hasMany('SliderAppTypeComponent'),
+  components: DS.hasMany('sliderAppTypeComponent'),
 
   /**
    * @type {object}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs
index 5031603..6acf985 100644
--- a/contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs
+++ b/contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs
@@ -15,17 +15,24 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-<h4>Available Types</h4>
+<h4>{{t wizard.step1.header}}</h4>
 <div class="row-fluid">
   <div class="span6">
-    {{view Ember.Select contentBinding="controller.types" multiple="true" class="type-select"}}
+    {{view view.availableTypesSelect contentBinding="controller.availableTypes" optionLabelPath="content.displayName" multiple="true" class="type-select"}}
   </div>
   <div class="span6">
-  <label>Name: {{input id="app-name-input"}}</label>
-    <h5>Description:</h5>
+    <div {{bind-attr class=":control-group controller.isNameError:error"}}>
+      <label>{{t common.name}}: {{input id="app-name-input" valueBinding="controller.newAppName"}}</label>
+    </div>
+    {{#if controller.isNameError}}
+      <div class="alert alert-error">
+        {{controller.nameErrorMessage}}
+      </div>
+    {{/if}}
+    <h5>{{t wizard.step1.description}}:</h5>
     <p>
-      Deploys HBase cluster on YARN.
+      {{controller.typeDescription}}
     </p>
   </div>
 </div>
-<button class="btn btn-success pull-right next-btn" {{action nextStep target="controller"}}>Next</button>
+<button class="btn btn-success pull-right next-btn" {{bind-attr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} &rarr;</button>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/translations.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/translations.js b/contrib/views/slider/src/main/resources/ui/app/translations.js
index f4a7401..933f083 100644
--- a/contrib/views/slider/src/main/resources/ui/app/translations.js
+++ b/contrib/views/slider/src/main/resources/ui/app/translations.js
@@ -20,7 +20,9 @@
 Em.I18n.translations = {
 
   'common' : {
-    'show': "Show"
+    'show': "Show",
+    'name': "Name",
+    'next': "Next"
   },
   'tableView.filters.all': 'All',
   'tableView.filters.filtered': 'Filtered',
@@ -37,6 +39,11 @@ Em.I18n.translations = {
 
   'wizard.name': 'Create Slider App',
   'wizard.step1.name': 'Select Type',
+  'wizard.step1.header': 'Available Types',
+  'wizard.step1.description': 'Description',
+  'wizard.step1.typeDescription': 'Deploys {0} cluster on YARN.',
+  'wizard.step1.nameFormatError': 'App Name should consist only of letters, numbers, \'-\', \'_\' and first character should be a letter.',
+  'wizard.step1.nameRepeatError': 'App with entered Name already exists.',
   'wizard.step2.name': 'Allocate Resources',
   'wizard.step3.name': 'Configuration',
   'wizard.step4.name': 'Deploy'

http://git-wip-us.apache.org/repos/asf/ambari/blob/d4afecaf/contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1.js
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1.js b/contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1.js
new file mode 100644
index 0000000..18312c9
--- /dev/null
+++ b/contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1.js
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+
+App.CreateAppWizardStep1View = Ember.View.extend({
+
+  didInsertElement: function () {
+    this.get('controller').loadStep();
+  },
+
+  availableTypesSelect: Ember.Select.extend({
+
+    /**
+     * Forbid user to select more than one App type
+     * Set selected type to <code>controller.selectedType</code>
+     */
+    setSelection: function () {
+      var content = this.get('content');
+      var selection = this.get('selection');
+      if (content.get('length') && !selection.length) {
+        this.set('selection', content.objectAt(0));
+      }
+      if (selection.length > 1) {
+        this.set('selection', [selection[0]])
+      }
+      this.set('controller.selectedType', this.get('selection')[0])
+    }.observes('content.length', 'selection.length', 'selection.@each')
+  })
+});