Преглед изворни кода

AMBARI-3709. Advanced Repo options UI and flow needs updating (xiwang)

Xi Wang пре 11 година
родитељ
комит
abaca9f8f9

+ 20 - 18
ambari-web/app/controllers/installer.js

@@ -372,28 +372,30 @@ App.InstallerController = App.WizardController.extend({
     var stackName = nameVersionCombo.split('-')[0];
     var stackVersion = nameVersionCombo.split('-')[1];
     if (selectedStack && selectedStack.operatingSystems) {
-      this.set('validationCnt', selectedStack.operatingSystems.length);
+      this.set('validationCnt', selectedStack.get('operatingSystems').filterProperty('selected', true).length);
       this.set('invalidCnt', 0);
       selectedStack.operatingSystems.forEach(function (os) {
-        os.validation = 'icon-repeat';
-        selectedStack.set('reload', !selectedStack.get('reload'));
-        App.ajax.send({
-          name: 'wizard.advanced_repositories.valid_url',
-          sender: this,
-          data: {
-            stackName: stackName,
-            stackVersion: stackVersion,
-            nameVersionCombo: nameVersionCombo,
-            osType: os.osType,
+        if (os.selected) {
+          os.validation = 'icon-repeat';
+          selectedStack.set('reload', !selectedStack.get('reload'));
+          App.ajax.send({
+            name: 'wizard.advanced_repositories.valid_url',
+            sender: this,
             data: {
-              'Repositories': {
-                'base_url': os.baseUrl
+              stackName: stackName,
+              stackVersion: stackVersion,
+              nameVersionCombo: nameVersionCombo,
+              osType: os.osType,
+              data: {
+                'Repositories': {
+                  'base_url': os.baseUrl
+                }
               }
-            }
-          },
-          success: 'checkRepoURLSuccessCallback',
-          error: 'checkRepoURLErrorCallback'
-        });
+            },
+            success: 'checkRepoURLSuccessCallback',
+            error: 'checkRepoURLErrorCallback'
+          });
+        }
       }, this);
     }
   },

+ 5 - 3
ambari-web/app/messages.js

@@ -269,15 +269,17 @@ Em.I18n.translations = {
   'installer.step1.header':'Select Stack',
   'installer.step1.body':'Please select the service stack that you want to use to install your Hadoop cluster.',
   'installer.step1.advancedRepo.title':'Advanced Repository Options',
-  'installer.step1.advancedRepo.message':'Specify the repository where software packages will be downloaded from. If your hosts do not have access to the internet, you will have to create a local mirror of the repository accessible by all hosts and specify the Base URL here.',
+  'installer.step1.advancedRepo.message':'Customize the repository Base URLs for downloading the Stack software packages. If your hosts do not have access to the internet, you will have to create a local mirror of the Stack repository that is accessible by all hosts and use those Base URLs shere.',
+  'installer.step1.advancedRepo.importantMassage':'<b>Important:</b> When using local mirror repositories, you only need to provide Base URLs for the Operating System you are installing for your Stack. Uncheck all other repositories.',
   'installer.step1.advancedRepo.localRepo.error.modifyUrl':'Local repository URL must be modified',
   'installer.step1.advancedRepo.localRepo.error.noUrl':'Base URL required for a local repository',
   'installer.step1.advancedRepo.localRepo.column.baseUrl':'Base URL',
   'installer.step1.advancedRepo.localRepo.label.os':'Operating System',
   'installer.step1.advancedRepo.localRepo.label.baseUrl':'Repository Base URL',
   'installer.step1.advancedRepo.localRepo.label.stack':'Stack',
-  'installer.step1.attentionNeeded':'<b>Attention:</b> All repository URLs are required before you can proceed.',
-  'installer.step1.invalidURLAttention': '<b>Attention:</b> Please make sure all repository URLs are valid.',
+  'installer.step1.attentionNeeded':'<b>Attention:</b> Repository URLs are REQUIRED before you can proceed.',
+  'installer.step1.invalidURLAttention': '<b>Attention:</b> Please make sure all repository URLs are valid before proceed.',
+  'installer.step1.checkAtLeastOneAttention': '<b>Attention:</b> Please check at least one repository.',
 
   'installer.step2.header':'Install Options',
   'installer.step2.body':'Enter the list of hosts to be included in the cluster and provide your SSH key.',

+ 45 - 7
ambari-web/app/styles/application.less

@@ -4750,31 +4750,69 @@ i.icon-asterisks {
         -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
         box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
       }
+      .disabled-textfield input{
+        color: #808080;
+        disabled: disabled;
+        pointer-events: none;
+        cursor: default;
+      }
+      .disabled-label {
+        color: #808080;
+      }
+      .group-checkbox {
+        width: 3%;
+        vertical-align: middle;
+        padding-left: 2px;
+        padding-right: 2px;
+      }
       .os {
-        width: 13%;
+        padding: 6px;
+        border-top: transparent;
+      }
+      .os-td {
+        width: 17%;
+        padding: 2px;
       }
       .url {
-        width: 70%;
+        width: 65%;
       }
       .url-results {
-        width: 70%;
+        width: 65%;
+        vertical-align: middle;
         .ember-text-field {
           width: 100%;
         }
       }
       .validation {
-        width: 7%;
+        width: 3%;
       }
       .validation-results {
-        width: 7%;
-        padding-top: 11px;
+        width: 3%;
+        vertical-align: middle;
+        padding-top: 0px;
+        padding-left: 4px;
+        padding-right: 4px;
+      }
+      .clearAll-icon {
+        width: 2%;
+        vertical-align: middle;
+        padding-top: 0px;
+        padding-left: 4px;
+        padding-right: 4px;
+        a {
+          cursor: pointer;
+          color: #808080;
+        }
       }
       .action {
         width: 10%;
       }
       .action-results {
         width: 10%;
-        padding-top: 11px;
+        vertical-align: middle;
+        padding-top: 0px;
+        padding-left: 4px;
+        padding-right: 4px;
         a {
           cursor: pointer;
         }

+ 46 - 25
ambari-web/app/templates/wizard/step1.hbs

@@ -35,12 +35,13 @@
     </div>
       <div  class="accordion-body collapse in">
         <div class="accordion-inner">
-          <div class="alert alert-info">
-            {{t installer.step1.advancedRepo.message}}
-          </div>
-          <table class="table table-striped">
+          <div class="alert alert-info">{{t installer.step1.advancedRepo.message}}</div>
+          <div class="alert alert-danger">{{t installer.step1.advancedRepo.importantMassage}}</div>
+
+          <table class="table">
             <thead>
             <tr>
+              <th></th>
               <th class="os">{{t common.os}}</th>
               <th class="url">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</th>
               <th class="validations"></th>
@@ -48,35 +49,55 @@
             </tr>
             </thead>
             <tbody>
-              {{#each repo in view.allRepositories}}
-              <tr>
-                <td  {{bindAttr class=":os repo.empty-error:label-error repo.invalid-error:label-error "}}>{{repo.osType}}</td>
-                <td  {{bindAttr class=":url-results repo.empty-error:textfield-error repo.invalid-error:textfield-error"}}>
-                    {{view Ember.TextField valueBinding="repo.baseUrl"}}
-                </td>
-                <td class="validation-results">
-                  {{#if repo.validation}}
-                    <i {{bindAttr class="repo.validation"}}></i>
-                  {{/if}}
-                </td>
-                <td class="action-results">
-                  {{#if repo.undo}}
-                    <a {{action "undoLocalRepository" repo target="view" }}>
-                      <i class="icon-undo"></i>{{t common.undo}}
-                    </a>
-                  {{/if}}
-                </td>
-              </tr>
+              {{#each repoGroup in view.allRepositoriesGroup}}
+                <tr>
+                  <td class="group-checkbox">{{view Ember.Checkbox checkedBinding="repoGroup.checked"}}</td>
+                  <td class="os-td">
+                    <table {{bindAttr class="repoGroup.checked::disabled-label"}}>
+                      <tbody>
+                      {{#each repo in repoGroup}}
+                        <tr>
+                          <td  {{bindAttr class=":os repo.empty-error:label-error repo.invalid-error:label-error "}}>{{repo.osType}}</td>
+                        </tr>
+                      {{/each}}
+                      </tbody>
+                    </table>
+                  </td>
+                  <td  {{bindAttr class=":url-results repoGroup.checked::disabled-textfield repoGroup.empty-error:textfield-error repoGroup.invalid-error:textfield-error"}}>
+                    {{view Ember.TextField valueBinding="repoGroup.baseUrl"}}
+                  </td>
+                  <td class="clearAll-icon">
+                    {{#if repoGroup.clearAll}}
+                      <a {{action "clearGroupLocalRepository" repoGroup target="view" }}>
+                        <i class="icon-remove-sign"></i>
+                      </a>
+                    {{/if}}
+                  </td>
+                  <td class="validation-results">
+                    {{#if repoGroup.validation}}
+                      <i {{bindAttr class="repoGroup.validation"}}></i>
+                    {{/if}}
+                  </td>
+                  <td class="action-results">
+                    {{#if repoGroup.undo}}
+                      <a {{action "undoGroupLocalRepository" repoGroup target="view" }}>
+                        <i class="icon-undo"></i>{{t common.undo}}
+                      </a>
+                    {{/if}}
+                  </td>
+                </tr>
               {{/each}}
             </tbody>
           </table>
-          {{#if view.isSubmitDisabled}}
+          {{#if view.emptyRepoExist}}
             <div class="alert">{{t installer.step1.attentionNeeded}}</div>
           {{/if}}
           {{#if view.invalidUrlExist}}
             <div class="alert">{{t installer.step1.invalidURLAttention}}</div>
           {{/if}}
-
+          {{#if view.allRepoUnchecked}}
+            <div class="alert">{{t installer.step1.checkAtLeastOneAttention}}</div>
+          {{/if}}
         </div>
       </div>
   </div>

+ 179 - 49
ambari-web/app/views/wizard/step1_view.js

@@ -45,75 +45,205 @@ App.WizardStep1View = Em.View.extend({
     }
   }),
 
-  allRepositories: [],
-  repoErrorCnt: function () {
-    return this.get('allRepositories').filterProperty('empty-error', true).length;
-  }.property('allRepositories.@each.empty-error'),
+  allRepositoriesGroup: [[],[],[]],
+  emptyRepoExist: function () {
+    return (this.get('allRepositoriesGroup').filterProperty('empty-error', true).length != 0);
+  }.property('allRepositoriesGroup.@each.empty-error'),
+  isSubmitDisabled: function() {
+    return this.get('emptyRepoExist') || this.get('allRepoUnchecked') ;
+  }.property('emptyRepoExist', 'allRepoUnchecked'),
+  invalidUrlExist: function () {
+    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
+    return (selectedStack.get('invalidCnt') > 0);
+  }.property('controller.content.stacks.@each.invalidCnt'),
+  allRepoUnchecked: function () {
+    return (!this.get('allRepositoriesGroup').filterProperty('checked', true).length);
+  }.property('allRepositoriesGroup.@each.checked'),
+
+  /**
+   * Onclick handler for Config Group Header. Used to show/hide block
+   */
+  onToggleBlock: function () {
+    this.$('.accordion-body').toggle('blind', 500);
+    this.set('isRLCollapsed', !this.get('isRLCollapsed'));
+  },
+  isRLCollapsed: true,
+  didInsertElement: function () {
+    if (this.get('isRLCollapsed')) {
+      this.$('.accordion-body').hide();
+    }
+  },
   loadRepositories: function () {
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    var repos = [];
+    var reposGroup = [[],[],[]];
+    var self = this;
     if (selectedStack && selectedStack.operatingSystems) {
       selectedStack.operatingSystems.forEach(function (os) {
-       var cur_repo = Em.Object.create({
-         baseUrl: os.baseUrl,
-         defaultBaseUrl: os.defaultBaseUrl,
-         osType: os.osType,
-         validation: os.validation
-       });
-        cur_repo.set('empty-error', !os.baseUrl);
-        cur_repo.set('invalid-error', os.validation == 'icon-remove');
-        cur_repo.set('undo', os.baseUrl != os.defaultBaseUrl);
-        repos.pushObject(cur_repo);
+        var cur_repo = Em.Object.create({
+          baseUrl: os.baseUrl
+        });
+        switch(os.osType) {
+          case 'redhat5':
+            cur_repo.set('osType', 'Red Hat 5');
+            reposGroup[0][0] = cur_repo;
+            // set group 0 properties by redhat5 (any of the three is ok)
+            self.setGroupByOs(reposGroup[0], os, 0);
+            break;
+          case 'centos5':
+            cur_repo.set('osType', 'CentOS 5');
+            reposGroup[0][1] = cur_repo;
+            break;
+          case 'oraclelinux5':
+            cur_repo.set('osType', 'Oracle Linux 5');
+            reposGroup[0][2] = cur_repo;
+            break;
+          case 'redhat6':
+            cur_repo.set('osType', 'Red Hat 6');
+            reposGroup[1][0] = cur_repo;
+            // set group 1 properties by redhat6 (any of the three is ok)
+            self.setGroupByOs(reposGroup[1], os, 1);
+            break;
+          case 'centos6':
+            cur_repo.set('osType', 'CentOS 6');
+            reposGroup[1][1] = cur_repo;
+            break;
+          case 'oraclelinux6':
+            cur_repo.set('osType', 'Oracle Linux 6');
+            reposGroup[1][2] = cur_repo;
+            break;
+          case 'sles11':
+            cur_repo.set('osType', 'SLES 11');
+            reposGroup[2][0] = cur_repo;
+            // set group 2 properties by sles11 (any of the twe is ok)
+            self.setGroupByOs(reposGroup[2], os, 2);
+            break;
+          case 'suse11':
+            cur_repo.set('osType', 'SUSE 11');
+            reposGroup[2][1] = cur_repo;
+            break;
+        }
       });
     }
-    this.set('allRepositories', repos);
+    this.set('allRepositoriesGroup', reposGroup);
   }.observes('controller.content.stacks.@each.isSelected', 'controller.content.stacks.@each.reload'),
-
-  undoLocalRepository: function (event) {
-    var localRepo = event.context;
-    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    var cos = selectedStack.operatingSystems.findProperty('osType', localRepo.osType);
-    cos.baseUrl = cos.defaultBaseUrl;
-    cos.validation = null;
-    this.loadRepositories();
+  setGroupByOs: function (group, os, groupNumber) {
+    var isChecked = this.get('allGroupsCheckbox')[groupNumber];
+    group.set('checked', isChecked);
+    group.set('baseUrl', os.baseUrl);
+    group.set('defaultBaseUrl', os.defaultBaseUrl);
+    group.set('empty-error', !os.baseUrl);
+    group.set('invalid-error', os.validation == 'icon-remove');
+    group.set('validation', os.validation);
+    group.set('undo', os.baseUrl != os.defaultBaseUrl);
+    group.set('clearAll', os.baseUrl);
+    group.set('group-number', groupNumber);
   },
-  editLocalRepository: function (event) {
+  /**
+   * Onclick handler for checkbox of each repo group
+   */
+  updateByCheckbox: function () {
     //upload to content
-    var repos = this.get('allRepositories');
+    var groups = this.get('allRepositoriesGroup');
+    var self = this;
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     if (selectedStack && selectedStack.operatingSystems) {
       selectedStack.operatingSystems.forEach(function (os) {
-        var target = repos.findProperty('osType', os.osType);
-        if ( os.baseUrl != target.get('baseUrl')) {
-          os.baseUrl = target.get('baseUrl');
+        var groupNumber = self.osTypeToGroup(os.osType);
+        var targetGroup = groups.findProperty('group-number', groupNumber);
+        if (!targetGroup.get('checked')) {
+          os.baseUrl = os.defaultBaseUrl;
           os.validation = null;
-          target.set('undo', target.get('baseUrl') != target.get('defaultBaseUrl'));
-          target.set('invalid-error', false);
-          target.set('validation', null);
-          target.set('empty-error',!target.get('baseUrl'));
+          os.selected = false;
+          targetGroup.set('baseUrl', os.defaultBaseUrl);
+          targetGroup.set('undo', targetGroup.get('baseUrl') != targetGroup.get('defaultBaseUrl'));
+          targetGroup.set('invalid-error', false);
+          targetGroup.set('validation', null);
+          targetGroup.set('clearAll', false);
+          targetGroup.set('empty-error',!targetGroup.get('baseUrl'));
+          self.get('allGroupsCheckbox')[groupNumber] = false;
+          self.set('allGroupsCheckbox', self.get('allGroupsCheckbox'));
+        } else {
+          os.selected = true;
+          targetGroup.set('clearAll', targetGroup.get('baseUrl'));
+          targetGroup.set('empty-error',!targetGroup.get('baseUrl'));
+          self.get('allGroupsCheckbox')[groupNumber] = true;
         }
       });
     }
-  }.observes('allRepositories.@each.baseUrl'),
-  isSubmitDisabled: function() {
-    return this.get('repoErrorCnt') != 0;
-  }.property('repoErrorCnt'),
-  invalidUrlExist: function () {
-    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    return (selectedStack.get('invalidCnt') > 0);
-  }.property('controller.content.stacks.@each.invalidCnt'),
+  }.observes('allRepositoriesGroup.@each.checked'),
 
+  allGroupsCheckbox: [true, true, true],
   /**
-   * Onclick handler for Config Group Header. Used to show/hide block
+   * Onclick handler for undo action of each repo group
    */
-  onToggleBlock: function () {
-    this.$('.accordion-body').toggle('blind', 500);
-    this.set('isRLCollapsed', !this.get('isRLCollapsed'));
+  undoGroupLocalRepository: function (event) {
+    var group = event.context;
+    var osTypes = this.groupToOsType(group.get('group-number'));
+    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
+    osTypes.forEach( function (os) {
+      var cos = selectedStack.operatingSystems.findProperty('osType', os );
+      cos.baseUrl = cos.defaultBaseUrl;
+      cos.validation = null;
+    });
+    this.loadRepositories();
   },
-  isRLCollapsed: true,
-  didInsertElement: function () {
-    if (this.get('isRLCollapsed')) {
-      this.$('.accordion-body').hide();
+  clearGroupLocalRepository: function (event) {
+    var group = event.context;
+    var osTypes = this.groupToOsType(group.get('group-number'));
+    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
+    osTypes.forEach( function (os) {
+      var cos = selectedStack.operatingSystems.findProperty('osType', os );
+      cos.baseUrl = '';
+      cos.validation = null;
+    });
+    this.loadRepositories();
+  },
+  /**
+   * Handler when editing any repo group BaseUrl
+   */
+  editGroupLocalRepository: function (event) {
+    //upload to content
+    var groups = this.get('allRepositoriesGroup');
+    var self = this;
+    var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
+    if (selectedStack && selectedStack.operatingSystems) {
+      selectedStack.operatingSystems.forEach(function (os) {
+        var targetGroup = groups.findProperty('group-number', self.osTypeToGroup(os.osType));
+        if (os.baseUrl != targetGroup.get('baseUrl')) {
+          os.baseUrl = targetGroup.get('baseUrl');
+          os.validation = null;
+          targetGroup.set('undo', targetGroup.get('baseUrl') != targetGroup.get('defaultBaseUrl'));
+          targetGroup.set('invalid-error', false);
+          targetGroup.set('validation', null);
+          targetGroup.set('clearAll', os.baseUrl);
+          targetGroup.set('empty-error',!targetGroup.get('baseUrl'));
+        }
+      });
+    }
+  }.observes('allRepositoriesGroup.@each.baseUrl'),
+  groupToOsType: function (groupNumber) {
+    switch (groupNumber) {
+      case 0:
+        return ['redhat5', 'centos5', 'oraclelinux5'];
+      case 1:
+        return ['redhat6', 'centos6', 'oraclelinux6'];
+      case 2:
+        return ['sles11', 'suse11'];
+    }
+  },
+  osTypeToGroup: function (osType) {
+    switch(osType) {
+      case 'redhat5':
+      case 'centos5':
+      case 'oraclelinux5':
+        return 0;
+      case 'redhat6':
+      case 'centos6':
+      case 'oraclelinux6':
+        return 1;
+      case 'sles11':
+      case 'suse11':
+        return 2;
     }
   }
 });