Jelajahi Sumber

AMBARI-5865. Provide 'Create App' Wizard Step2 functionallity. (akovalenko)

Aleksandr Kovalenko 11 tahun lalu
induk
melakukan
6d9f0d3dbc

+ 5 - 6
contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1.js → contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js

@@ -70,12 +70,10 @@ App.CreateAppWizardStep1Controller = Ember.Controller.extend({
    * 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()});
-    }
+    var newApp = Ember.Object.create({
+      name: '',
+      appType: null
+    });
     this.set('newApp', newApp);
   },
 
@@ -131,6 +129,7 @@ App.CreateAppWizardStep1Controller = Ember.Controller.extend({
     var newApp = this.get('newApp');
     newApp.set('appType', this.get('selectedType'));
     newApp.set('name', this.get('newAppName'));
+    this.set('appWizardController.newApp', newApp);
   },
 
   actions: {

+ 114 - 0
contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step2_controller.js

@@ -0,0 +1,114 @@
+/**
+ * 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.CreateAppWizardStep2Controller = Ember.ArrayController.extend({
+
+  needs: "createAppWizard",
+
+  appWizardController: Ember.computed.alias("controllers.createAppWizard"),
+
+  content: [],
+
+  /**
+   * New App object
+   * @type {App.SliderApp}
+   */
+  newApp: null,
+
+  /**
+   * Load all required data for step
+   */
+  loadStep: function () {
+    this.initializeNewApp();
+  },
+
+  /**
+   * Initialize new App to use it scope of controller
+   */
+  initializeNewApp: function () {
+    var newApp = this.get('appWizardController.newApp');
+    this.set('newApp', newApp);
+  },
+
+  /**
+   * Fill <code>content</code> with objects created from <code>App.SliderAppTypeComponent</code>
+   */
+  loadTypeComponents: function () {
+    var content = [];
+    var allTypeComponents = this.get('newApp.appType.components');
+    if (allTypeComponents && allTypeComponents.get('length')) {
+      allTypeComponents.forEach(function (typeComponent) {
+        content.push(Ember.Object.create({
+          name: typeComponent.get('displayName'),
+          numInstances: typeComponent.get('defaultNumInstances'),
+          yarnMemory: typeComponent.get('defaultYARNMemory'),
+          yarnCPU: typeComponent.get('defaultYARNCPU')
+        }));
+      });
+      this.set('content', content);
+    }
+  }.observes('newApp.appType.components.length'),
+
+  /**
+   * Validate all input fields are integer
+   * @return {Boolean}
+   */
+  isError: function () {
+    var result = false;
+    this.get('content').forEach(function (component) {
+      if (!result && (this.isNotInteger(component.get('numInstances')) || this.isNotInteger(component.get('yarnMemory')) || this.isNotInteger(component.get('yarnCPU')))) {
+        result = true;
+      }
+    }, this);
+    return result;
+  }.property('content.@each.numInstances', 'content.@each.yarnMemory', 'content.@each.yarnCPU'),
+
+  /**
+   * Check if param is integer
+   * @param value value to check
+   * @return {Boolean}
+   */
+  isNotInteger: function (value) {
+    return !value || !(value % 1 == 0);
+  },
+
+  /**
+   * Define if submit button is disabled
+   * <code>isError</code> should be true
+   */
+  isSubmitDisabled: function () {
+    return this.get('isError');
+  }.property('isError'),
+
+  /**
+   * Save all data about components to <code>appWizardController.newApp.components</code>
+   */
+  saveComponents: function () {
+    this.set('appWizardController.newApp.components', this.get('content'));
+  },
+
+  actions: {
+    /**
+     * Save data and proceed to the next step
+     */
+    submit: function () {
+      this.saveComponents();
+      this.get('appWizardController').nextStep();
+    }
+  }
+});

+ 2 - 0
contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard.js → contrib/views/slider/src/main/resources/ui/app/controllers/create_app_wizard_controller.js

@@ -18,6 +18,8 @@
 
 App.CreateAppWizardController = Ember.ObjectController.extend({
 
+  newApp: null,
+
   currentStep: 1,
 
   TOTAL_STEPS_NUMBER: 4,

+ 1 - 2
contrib/views/slider/src/main/resources/ui/app/models/slider_app.js

@@ -253,6 +253,5 @@ App.SliderApp.FIXTURES = [
 App.SliderApp.Status = {
   running: "Running",
   frozen: "Frozen",
-  destroyed: "Destroyed",
-  initialized: "Initialized"
+  destroyed: "Destroyed"
 };

+ 0 - 0
contrib/views/slider/src/main/resources/ui/app/routes/createAppWizard.js → contrib/views/slider/src/main/resources/ui/app/routes/create_app_wizard.js


+ 25 - 8
contrib/views/slider/src/main/resources/ui/app/styles/application.less

@@ -318,7 +318,15 @@ a {
   width: 60%;
   margin: -250px 0 auto;
   left: 20%;
-
+  .wizard-nav {
+    padding-left: 0px;
+  }
+  h5 {
+    font-weight: bold;
+  }
+  .slider-modal-body {
+    max-height: 505px;
+  }
   .next-btn {
     margin-left: 5px;
   }
@@ -338,12 +346,21 @@ a {
       list-style: none;
     }
   }
-  .step2-input {
-    width: 80%;
-    margin: 5% 10%;
-  }
-  .components-table {
-    margin-bottom: 30px;
+  #step2 {
+    .table-container {
+      max-height: 225px;
+      border: 1px solid #e3e3e3;
+      padding: 5px;
+      margin-bottom: 20px;
+      overflow-y: auto;
+      border-radius: 4px;
+      .components-table {
+        width: 100%;
+        border-spacing: 10px;
+        border-collapse: separate;
+      }
+      margin-bottom: 30px;
+    }
   }
 }
 .app-page {
@@ -476,4 +493,4 @@ a {
 
 .slider-modal-footer .btn-group .btn + .btn {
   margin-left: -1px;
-}
+}

+ 13 - 17
contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard.hbs

@@ -21,25 +21,21 @@
     <h3 id="myModalLabel">{{t wizard.name}}</h3>
   </div>
   <div class="slider-modal-body">
-    <div class="wizard">
-      <div class="container">
-        <div class="container-fluid">
-          <div class="row-fluid">
-            <div class="col-md-3">
-              <div class="well">
-                <ul class="nav nav-pills nav-stacked">
-                  <li {{bind-attr class="view.isStep1:active view.isStep1Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 1 target="controller"}}>{{t wizard.step1.name}}</a></li>
-                  <li {{bind-attr class="view.isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 2 target="controller"}}>{{t wizard.step2.name}}</a></li>
-                  <li {{bind-attr class="view.isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 3 target="controller"}}>{{t wizard.step3.name}}</a></li>
-                  <li {{bind-attr class="view.isStep4:active view.isStep4Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 4 target="controller"}}>{{t wizard.step4.name}}</a></li>
-                </ul>
-              </div>
-            </div>
-            <div class="wizard-content well col-md-9">
-              {{outlet}}
-            </div>
+    <div class="container-fluid">
+      <div class="row">
+        <div class="col-md-3 wizard-nav">
+          <div class="well">
+            <ul class="nav nav-pills nav-stacked">
+              <li {{bind-attr class="view.isStep1:active view.isStep1Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 1 target="controller"}}>{{t wizard.step1.name}}</a></li>
+              <li {{bind-attr class="view.isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 2 target="controller"}}>{{t wizard.step2.name}}</a></li>
+              <li {{bind-attr class="view.isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 3 target="controller"}}>{{t wizard.step3.name}}</a></li>
+              <li {{bind-attr class="view.isStep4:active view.isStep4Disabled:disabled"}}><a href="javascript:void(null);" {{action gotoStep 4 target="controller"}}>{{t wizard.step4.name}}</a></li>
+            </ul>
           </div>
         </div>
+        <div class="wizard-content well col-md-9">
+          {{outlet}}
+        </div>
       </div>
     </div>
   </div>

+ 2 - 2
contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step1.hbs

@@ -16,7 +16,7 @@
 * limitations under the License.
 }}
 <h4>{{t wizard.step1.header}}</h4>
-<div class="row-fluid">
+<div class="row">
   <div class="col-md-6">
     {{view view.availableTypesSelect contentBinding="controller.availableTypes" optionLabelPath="content.displayName" multiple="true" class="type-select"}}
   </div>
@@ -25,7 +25,7 @@
       <label>{{t common.name}}: {{input id="app-name-input" valueBinding="controller.newAppName"}}</label>
     </div>
     {{#if controller.isNameError}}
-      <div class="alert alert-error">
+      <div class="alert alert-danger">
         {{controller.nameErrorMessage}}
       </div>
     {{/if}}

+ 38 - 37
contrib/views/slider/src/main/resources/ui/app/templates/createAppWizard/step2.hbs

@@ -15,40 +15,41 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-
-<p>
-  HBase	applica;on	requires	resources	to	be	allocated	on	the	cluster.
-  Provide	resource	allocation	requests	for	each	component	of	the	application	below.
-</p>
-<table class="components-table">
-  <thead>
-  <tr>
-    <th></th>
-    <th>
-      Number of Instances
-    </th>
-    <th>
-      YARN Memory (MB)
-    </th>
-    <th>
-      YARN CPU Cores
-    </th>
-  </tr>
-  </thead>
-  <tbody>
-  <tr>
-    <td>HBASE_MASTER</td>
-    <td>{{input class="step2-input"}}</td>
-    <td>{{input class="step2-input"}}</td>
-    <td>{{input class="step2-input"}}</td>
-  </tr>
-  <tr>
-    <td>HBASE_REGIONSERVER</td>
-    <td>{{input class="step2-input"}}</td>
-    <td>{{input class="step2-input"}}</td>
-    <td>{{input class="step2-input"}}</td>
-  </tr>
-  </tbody>
-</table>
-<button class="btn btn-success pull-right next-btn" {{action nextStep}}>Next</button>
-<button class="btn pull-right" {{action prevStep}}>Back</button>
+<div id="step2">
+  <p>
+    {{t wizard.step2.header}}
+  </p>
+  <div class="table-container">
+    <table class="components-table">
+      <thead>
+      <tr>
+        <th></th>
+        <th>
+          {{t wizard.step2.table.instances}}
+        </th>
+        <th>
+          {{t wizard.step2.table.memory}}
+        </th>
+        <th>
+          {{t wizard.step2.table.cpu}}
+        </th>
+      </tr>
+      </thead>
+      <tbody>
+      {{#each}}
+        <tr>
+          <td>{{name}}</td>
+          <td>{{input valueBinding="numInstances"}}</td>
+          <td>{{input valueBinding="yarnMemory"}}</td>
+          <td>{{input valueBinding="yarnCPU"}}</td>
+        </tr>
+      {{/each}}
+      </tbody>
+    </table>
+  </div>
+  {{#if controller.isError}}
+    <div class="alert alert-danger">{{t wizard.step2.error.numbers}}</div>
+  {{/if}}
+  <button class="btn btn-success pull-right next-btn" {{bind-attr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}}</button>
+  <button class="btn pull-right" {{action prevStep}}>{{t common.back}}</button>
+</div>

+ 6 - 0
contrib/views/slider/src/main/resources/ui/app/translations.js

@@ -26,6 +26,7 @@ Em.I18n.translations = {
     'actions': 'Actions',
     'cancel': 'Cancel',
     'name': "Name",
+    'back': "Back",
     'value': "Value",
     'next': "Next",
     'quickLinks': "Quick Links",
@@ -58,6 +59,11 @@ Em.I18n.translations = {
   '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.step2.header': 'HBase application requires resources to be allocated on the cluster. Provide resource allocation requests for each component of the application below.',
+  'wizard.step2.table.instances': 'Number of Instances',
+  'wizard.step2.table.memory': 'YARN Memory (MB)',
+  'wizard.step2.table.cpu': 'Number of Instances',
+    'wizard.step2.error.numbers': 'All fields should be filled. Only integer numbers allowed.',
   'wizard.step3.name': 'Configuration',
   'wizard.step4.name': 'Deploy'
 };

+ 0 - 0
contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1.js → contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step1_view.js


+ 5 - 2
contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/createAppWizard.js → contrib/views/slider/src/main/resources/ui/app/views/createAppWizard/step2_view.js

@@ -16,6 +16,9 @@
  * limitations under the License.
  */
 
-App.CreateAppWizardStep1Controller = Ember.ObjectController.extend({
-  types: ['HBase', 'Pig']
+App.CreateAppWizardStep2View = Ember.View.extend({
+
+  didInsertElement: function () {
+    this.get('controller').loadStep();
+  }
 });

+ 0 - 0
contrib/views/slider/src/main/resources/ui/app/views/createAppWizard.js → contrib/views/slider/src/main/resources/ui/app/views/create_app_wizard_view.js