浏览代码

AMBARI-5756. Multiple repositories support in UI installation wizard. (akovalenko)

Aleksandr Kovalenko 11 年之前
父节点
当前提交
d56db548d8

文件差异内容过多而无法显示
+ 694 - 258
ambari-web/app/assets/data/wizard/stack/HDP_versions.json


+ 3 - 9
ambari-web/app/assets/data/wizard/stack/stacks2.json

@@ -1,17 +1,11 @@
 {
 {
-  "href" : "http://dev.hortonworks.com:8080/api/v1/stacks2",
+  "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks2?_=1399980862861",
   "items" : [
   "items" : [
     {
     {
-      "href" : "http://dev.hortonworks.com:8080/api/v1/stacks2/HDP",
+      "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks2/HDP",
       "Stacks" : {
       "Stacks" : {
         "stack_name" : "HDP"
         "stack_name" : "HDP"
       }
       }
-    },
-    {
-      "href" : "http://dev.hortonworks.com:8080/api/v1/stacks2/HDPLocal",
-      "Stacks" : {
-        "stack_name" : "HDPLocal"
-      }
     }
     }
   ]
   ]
-}
+}

+ 21 - 21
ambari-web/app/controllers/installer.js

@@ -311,20 +311,21 @@ App.InstallerController = App.WizardController.extend({
         version.operatingSystems.forEach(function (os) {
         version.operatingSystems.forEach(function (os) {
           if (os.repositories) {
           if (os.repositories) {
             os.repositories.forEach(function (repo) {
             os.repositories.forEach(function (repo) {
-              if(repo.Repositories.repo_name == version.Versions.stack_name) {
-                var defaultBaseUrl = repo.Repositories.default_base_url || repo.Repositories.base_url;
-                var latestBaseUrl = repo.Repositories.latest_base_url || defaultBaseUrl;
-                if (!App.supports.ubuntu && os.OperatingSystems.os_type == 'debian12') return; // @todo: remove after Ubuntu support confirmation
-                oses.push({
-                  osType: os.OperatingSystems.os_type,
-                  baseUrl: latestBaseUrl,
-                  latestBaseUrl: latestBaseUrl,
-                  originalLatestBaseUrl: latestBaseUrl,
-                  originalBaseUrl: repo.Repositories.base_url,
-                  defaultBaseUrl: defaultBaseUrl,
-                  mirrorsList: repo.Repositories.mirrors_list
-                });
-              }
+              var defaultBaseUrl = repo.Repositories.default_base_url || repo.Repositories.base_url;
+              var latestBaseUrl = repo.Repositories.latest_base_url || defaultBaseUrl;
+              if (!App.supports.ubuntu && os.OperatingSystems.os_type == 'debian12') return; // @todo: remove after Ubuntu support confirmation
+              oses.push({
+                osType: os.OperatingSystems.os_type,
+                baseUrl: latestBaseUrl,
+                latestBaseUrl: latestBaseUrl,
+                originalLatestBaseUrl: latestBaseUrl,
+                originalBaseUrl: repo.Repositories.base_url,
+                defaultBaseUrl: defaultBaseUrl,
+                mirrorsList: repo.Repositories.mirrors_list,
+                id: os.OperatingSystems.os_type + repo.Repositories.repo_name,
+                repoId: repo.Repositories.repo_id,
+                selected: true
+              });
             });
             });
           }
           }
         });
         });
@@ -488,9 +489,8 @@ App.InstallerController = App.WizardController.extend({
 
 
   /**
   /**
    * Check validation of the customized local urls
    * Check validation of the customized local urls
-   * @param stepController step1WizardController
    */
    */
-  checkRepoURL: function (stepController) {
+  checkRepoURL: function () {
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     selectedStack.set('reload', true);
     selectedStack.set('reload', true);
     var nameVersionCombo = selectedStack.name;
     var nameVersionCombo = selectedStack.name;
@@ -512,8 +512,9 @@ App.InstallerController = App.WizardController.extend({
             data: {
             data: {
               stackName: stackName,
               stackName: stackName,
               stackVersion: stackVersion,
               stackVersion: stackVersion,
-              nameVersionCombo: nameVersionCombo,
+              repoId: os.repoId,
               osType: os.osType,
               osType: os.osType,
+              osId: os.id,
               data: {
               data: {
                 'Repositories': {
                 'Repositories': {
                   'base_url': os.baseUrl,
                   'base_url': os.baseUrl,
@@ -539,7 +540,7 @@ App.InstallerController = App.WizardController.extend({
     console.log('Success in check Repo URL. data osType: ' + data.osType );
     console.log('Success in check Repo URL. data osType: ' + data.osType );
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     if (selectedStack && selectedStack.operatingSystems) {
     if (selectedStack && selectedStack.operatingSystems) {
-      var os = selectedStack.operatingSystems.findProperty('osType', data.osType);
+      var os = selectedStack.operatingSystems.findProperty('id', data.osId);
       os.validation = 'icon-ok';
       os.validation = 'icon-ok';
       selectedStack.set('reload', !selectedStack.get('reload'));
       selectedStack.set('reload', !selectedStack.get('reload'));
       this.set('validationCnt', this.get('validationCnt') - 1);
       this.set('validationCnt', this.get('validationCnt') - 1);
@@ -549,12 +550,11 @@ App.InstallerController = App.WizardController.extend({
   /**
   /**
    * onError callback for check Repo URL.
    * onError callback for check Repo URL.
    */
    */
-  checkRepoURLErrorCallback: function (request, ajaxOptions, error, data) {
+  checkRepoURLErrorCallback: function (request, ajaxOptions, error, data, params) {
     console.log('Error in check Repo URL. The baseURL sent is:  ' + data.data);
     console.log('Error in check Repo URL. The baseURL sent is:  ' + data.data);
-    var osType = data.url.split('/')[8];
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     if (selectedStack && selectedStack.operatingSystems) {
     if (selectedStack && selectedStack.operatingSystems) {
-      var os = selectedStack.operatingSystems.findProperty('osType', osType);
+      var os = selectedStack.operatingSystems.findProperty('id', params.osId);
       os.validation = 'icon-exclamation-sign';
       os.validation = 'icon-exclamation-sign';
       os.errorTitle = request.status + ":" + request.statusText;
       os.errorTitle = request.status + ":" + request.statusText;
       os.errorContent = $.parseJSON(request.responseText) ? $.parseJSON(request.responseText).message : "";
       os.errorContent = $.parseJSON(request.responseText) ? $.parseJSON(request.responseText).message : "";

+ 1 - 1
ambari-web/app/controllers/wizard/step8_controller.js

@@ -963,7 +963,7 @@ App.WizardStep8Controller = Em.Controller.extend({
           name: 'wizard.step8.set_local_repos',
           name: 'wizard.step8.set_local_repos',
           data: {
           data: {
             osType: os.osType,
             osType: os.osType,
-            name: stack.name,
+            repoId: os.repoId,
             stack2VersionURL: App.get('stack2VersionURL'),
             stack2VersionURL: App.get('stack2VersionURL'),
             data: JSON.stringify({
             data: JSON.stringify({
               "Repositories": {
               "Repositories": {

+ 1 - 1
ambari-web/app/routes/installer.js

@@ -144,7 +144,7 @@ module.exports = Em.Route.extend({
         installerController.set('validationCnt', 0);
         installerController.set('validationCnt', 0);
         installerController.set('invalidCnt', 0);
         installerController.set('invalidCnt', 0);
       } else {
       } else {
-        installerController.checkRepoURL(wizardStep1Controller);
+        installerController.checkRepoURL();
       }
       }
       // make sure got all validations feedback and no invalid url, then proceed
       // make sure got all validations feedback and no invalid url, then proceed
       var myVar = setInterval(
       var myVar = setInterval(

+ 73 - 77
ambari-web/app/styles/application.less

@@ -5852,19 +5852,85 @@ i.icon-asterisks {
     }
     }
   }
   }
   .accordion-body {
   .accordion-body {
-    .table thead {
-    }
-    .table tbody{
-      .label-error{
-        color: #b94a48;
+    .repositories-table {
+      div {
+        float: left;
+        min-height: 1px;
+      }
+      .thead {
+        width: 100%;
+        .th {
+          font-weight: bold;
+        }
+        .first-th {
+          width: 4%;
+        }
+        .os-th {
+          width: 13%;
+        }
+        .name-th {
+          width: 17%;
+        }
+        .url-th {
+          width: 66%;
+        }
+      }
+      .tbody {
+        width: 100%;
+        .trow {
+          width: 100%;
+          border-top: 1px solid #dddddd;
+          padding-top: 10px;
+          .os-td {
+            width: 17%;
+          }
+          .sub-trow {
+            width: 100%;
+            .name-td {
+              width: 16%;
+            }
+            .validation-td {
+              width: 4%;
+            }
+            .url-td {
+              width: 63%;
+              .ember-text-field {
+                width: 100%;
+              }
+            }
+            .clear-td {
+              width: 4%;
+              padding-top: 5px;
+              padding-left: 12px;
+              a {
+                cursor: pointer;
+                text-decoration: none;
+              }
+              .icon-remove-sign {
+                color: #808080;
+              }
+            }
+            .actions-td {
+              width: 10%;
+              padding-top: 5px;
+              a {
+                cursor: pointer;
+              }
+              .icon-undo {
+                color: rgb(243, 178, 11);
+                margin-right: 2px;
+              }
+            }
+          }
+        }
       }
       }
-      .textfield-error input{
+      .textfield-error input {
         border-color: #b94a48;
         border-color: #b94a48;
         -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
         -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
         -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
         -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);
         box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
       }
       }
-      .disabled-textfield input{
+      .disabled-textfield input {
         color: #808080;
         color: #808080;
         disabled: disabled;
         disabled: disabled;
         pointer-events: none;
         pointer-events: none;
@@ -5874,76 +5940,6 @@ i.icon-asterisks {
       .disabled-label {
       .disabled-label {
         color: #808080;
         color: #808080;
       }
       }
-      .group-checkbox {
-        width: 3%;
-        vertical-align: middle;
-        padding-left: 2px;
-        padding-right: 2px;
-      }
-      .os {
-        padding: 2px;
-        border-top: transparent;
-      }
-      .os-td {
-        width: 17%;
-        padding: 2px;
-        vertical-align: middle;
-      }
-      .url {
-        width: 65%;
-      }
-      .url-results {
-        width: 65%;
-        vertical-align: middle;
-        .ember-text-field {
-          width: 100%;
-        }
-      }
-      .validation {
-        width: 3%;
-      }
-      .validation-results {
-        width: 3%;
-        vertical-align: middle;
-        padding-top: 0px;
-        padding-left: 4px;
-        padding-right: 4px;
-        .icon-exclamation-sign {
-          color: #b94a48;
-        }
-
-      }
-      .clearAll-icon {
-        width: 2%;
-        vertical-align: middle;
-        padding-top: 0px;
-        padding-left: 4px;
-        padding-right: 4px;
-        a {
-          cursor: pointer;
-          text-decoration: none;
-        }
-        .icon-remove-sign {
-          color: #808080;
-        }
-      }
-      .action {
-        width: 10%;
-      }
-      .action-results {
-        width: 10%;
-        vertical-align: middle;
-        padding-top: 0px;
-        padding-left: 4px;
-        padding-right: 4px;
-        a {
-          cursor: pointer;
-        }
-        .icon-undo {
-          color: rgb(243, 178, 11);
-          margin-right: 2px;
-        }
-      }
     }
     }
     #skip-validation {
     #skip-validation {
       .checkbox {
       .checkbox {

+ 49 - 55
ambari-web/app/templates/wizard/step1.hbs

@@ -44,57 +44,55 @@
           <div class="alert alert-info">{{t installer.step1.advancedRepo.message}}</div>
           <div class="alert alert-info">{{t installer.step1.advancedRepo.message}}</div>
           <div class="alert alert-warning">{{t installer.step1.advancedRepo.importantMassage}}</div>
           <div class="alert alert-warning">{{t installer.step1.advancedRepo.importantMassage}}</div>
 
 
-          <table class="table">
-            <thead>
-            <tr>
-              <th></th>
-              <th class="os">{{t common.os}}</th>
-              <th class="validations"></th>
-              <th class="url">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</th>
-              <th class="actions"></th>
-            </tr>
-            </thead>
-            <tbody>
-              {{#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 class="validation-results">
-                  {{#if repoGroup.validation}}
-                    {{view view.popoverView repoGroupBinding="repoGroup"}}
-                  {{/if}}
-                </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="action-results">
-                  {{#if repoGroup.undo}}
-                    <a {{action "undoGroupLocalRepository" repoGroup target="view" }}>
-                      <i class="icon-undo"></i>{{t common.undo}}
-                    </a>
-                  {{/if}}
-                </td>
-              </tr>
+          <div class="repositories-table">
+            <div class="thead">
+              <div class="first-th">&nbsp;</div>
+              <div class="th os-th">{{t common.os}}</div>
+              <div class="th name-th">{{t common.name}}</div>
+              <div class="th url-th">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</div>
+            </div>
+            <div class="tbody">
+              {{#each repoGroup in view.allRepositoriesGroups}}
+                <div class="trow">
+                  <div class="os-td">
+                    <label>
+                      {{view Ember.Checkbox checkedBinding="repoGroup.checked"}}
+                      <span {{bindAttr class=":os repoGroup.checked::disabled-label"}}>{{repoGroup.name}}</span>
+                    </label>
+                  </div>
+                  <div style="width:83%">
+                    {{#each repository in repoGroup.repositories}}
+                        <div class="sub-trow">
+                          <div class="name-td">{{repository.repoId}}</div>
+                          <div class="validation-td">
+                            {{#if repository.validation}}
+                              {{view view.popoverView repoGroupBinding="repository"}}
+                            {{/if}}
+                          </div>
+                          <div {{bindAttr class=":url-td repoGroup.checked::disabled-textfield repository.empty-error:textfield-error repository.invalid-error:textfield-error"}}>
+                            {{view Ember.TextField valueBinding="repository.baseUrl"}}
+                          </div>
+                          <div class="clear-td">
+                            {{#if repository.clearAll}}
+                              <a {{action "clearGroupLocalRepository" repository target="view" }}>
+                                <i class="icon-remove-sign"></i>
+                              </a>
+                            {{/if}}
+                          </div>
+                          <div class="actions-td">
+                            {{#if repository.undo}}
+                              <a {{action "undoGroupLocalRepository" repository target="view" }}>
+                                <i class="icon-undo"></i>{{t common.undo}}
+                              </a>
+                            {{/if}}
+                          </div>
+                         </div>
+                    {{/each}}
+                  </div>
+                </div>
               {{/each}}
               {{/each}}
-            </tbody>
-          </table>
+            </div>
+          </div>
           <div id="skip-validation">
           <div id="skip-validation">
             <label>{{view Ember.Checkbox checkedBinding="view.skipValidationChecked" class="checkbox"}}{{t installer.step1.advancedRepo.skipValidation.message}}
             <label>{{view Ember.Checkbox checkedBinding="view.skipValidationChecked" class="checkbox"}}{{t installer.step1.advancedRepo.skipValidation.message}}
               <i class="icon-question-sign" rel="skip-validation-tooltip"
               <i class="icon-question-sign" rel="skip-validation-tooltip"
@@ -116,8 +114,4 @@
 {{/if}}
 {{/if}}
 
 
 <a class="btn pull-left" {{action back}}>&larr; {{t common.back}}</a>
 <a class="btn pull-left" {{action back}}>&larr; {{t common.back}}</a>
-{{#if view.isSubmitDisabled}}
-  <a class="btn btn-success pull-right" disabled="disabled">{{t common.next}} &rarr;</a>
-{{else}}
-  <a class="btn btn-success pull-right" {{action next}}>{{t common.next}} &rarr;</a>
-{{/if}}
+<button class="btn btn-success pull-right" {{bindAttr disabled="view.isSubmitDisabled"}} {{action next}}>{{t common.next}} &rarr;</button>

+ 2 - 2
ambari-web/app/utils/ajax/ajax.js

@@ -1323,7 +1323,7 @@ var urls = {
     'mock': '/data/wizard/{mock}'
     'mock': '/data/wizard/{mock}'
   },
   },
   'wizard.advanced_repositories.valid_url': {
   'wizard.advanced_repositories.valid_url': {
-    'real': '/stacks2/{stackName}/versions/{stackVersion}/operatingSystems/{osType}/repositories/{nameVersionCombo}',
+    'real': '/stacks2/{stackName}/versions/{stackVersion}/operatingSystems/{osType}/repositories/{repoId}',
     'mock': '',
     'mock': '',
     'type': 'PUT',
     'type': 'PUT',
     'format': function (data) {
     'format': function (data) {
@@ -1571,7 +1571,7 @@ var urls = {
   },
   },
 
 
   'wizard.step8.set_local_repos': {
   'wizard.step8.set_local_repos': {
-    'real':'{stack2VersionURL}/operatingSystems/{osType}/repositories/{name}',
+    'real':'{stack2VersionURL}/operatingSystems/{osType}/repositories/{repoId}',
     'mock':'',
     'mock':'',
     'format': function(data) {
     'format': function(data) {
       return {
       return {

+ 87 - 156
ambari-web/app/views/wizard/step1_view.js

@@ -34,23 +34,41 @@ App.WizardStep1View = Em.View.extend({
     });
     });
   }.property('controller.content.stacks.@each.isSelected'),
   }.property('controller.content.stacks.@each.isSelected'),
 
 
+  /**
+   * List of all repositories
+   * @type {Array}
+   */
+  allRepositories: [],
+
   /**
   /**
    * List of all repo-groups
    * List of all repo-groups
-   * @type {Object[][]}
+   * @type {Array}
    */
    */
-  allRepositoriesGroup: [
-    [],
-    [],
-    []
-  ],
+  allRepositoriesGroups: function () {
+    var result = [];
+    var stacks = this.get('controller.content.stacks');
+    if (stacks && stacks.length) {
+      var selectedStack = stacks.findProperty('isSelected', true);
+      var allRepositories = this.get('allRepositories');
+      var OSNames = allRepositories.mapProperty('osType').uniq();
+      OSNames.forEach(function (os) {
+        result.push(Ember.Object.create({
+          checked: selectedStack.operatingSystems.findProperty('osType', os).selected,
+          name: os,
+          repositories: allRepositories.filterProperty('osType', os)
+        }));
+      });
+    }
+    return result;
+  }.property('allRepositories.length', 'controller.content.stacks'),
 
 
   /**
   /**
    * Verify if some repo has empty base-url
    * Verify if some repo has empty base-url
    * @type {bool}
    * @type {bool}
    */
    */
   emptyRepoExist: function () {
   emptyRepoExist: function () {
-    return this.get('allRepositoriesGroup').someProperty('empty-error', true);
-  }.property('allRepositoriesGroup.@each.empty-error'),
+    return this.get('allRepositories').someProperty('empty-error', true);
+  }.property('allRepositories.@each.empty-error'),
 
 
   /**
   /**
    * Disable submit button flag
    * Disable submit button flag
@@ -66,25 +84,25 @@ App.WizardStep1View = Em.View.extend({
    */
    */
   invalidUrlExist: function () {
   invalidUrlExist: function () {
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    var invalidExist = this.get('allRepositoriesGroup').someProperty('validation', 'icon-exclamation-sign');
+    var invalidExist = this.get('allRepositories').someProperty('validation', 'icon-exclamation-sign');
     return (selectedStack.get('invalidCnt') > 0) && invalidExist;
     return (selectedStack.get('invalidCnt') > 0) && invalidExist;
-  }.property('controller.content.stacks.@each.invalidCnt', 'allRepositoriesGroup.@each.validation'),
+  }.property('controller.content.stacks.@each.invalidCnt', 'allRepositories.@each.validation'),
 
 
   /**
   /**
    * If all repo links are unchecked
    * If all repo links are unchecked
    * @type {bool}
    * @type {bool}
    */
    */
   allRepoUnchecked: function () {
   allRepoUnchecked: function () {
-    return !this.get('allRepositoriesGroup').someProperty('checked', true);
-  }.property('allRepositoriesGroup.@each.checked'),
+    return !this.get('allRepositoriesGroups').someProperty('checked', true);
+  }.property('allRepositoriesGroups.@each.checked'),
 
 
   /**
   /**
    * Overall errors count
    * Overall errors count
    * @type {number}
    * @type {number}
    */
    */
   totalErrorCnt: function () {
   totalErrorCnt: function () {
-    var emptyCnt = this.get('allRepositoriesGroup').filterProperty('empty-error', true).length;
-    var invalidCnt = this.get('allRepositoriesGroup').filterProperty('validation', 'icon-exclamation-sign').length;
+    var emptyCnt = this.get('allRepositories').filterProperty('empty-error', true).length;
+    var invalidCnt = this.get('allRepositories').filterProperty('validation', 'icon-exclamation-sign').length;
     if (this.get('allRepoUnchecked')) {
     if (this.get('allRepoUnchecked')) {
       return 1;
       return 1;
     } else if (emptyCnt || invalidCnt) {
     } else if (emptyCnt || invalidCnt) {
@@ -92,7 +110,7 @@ App.WizardStep1View = Em.View.extend({
     } else {
     } else {
       return 0;
       return 0;
     }
     }
-  }.property('allRepositoriesGroup.@each.empty-error', 'allRepoUnchecked', 'allRepositoriesGroup.@each.validation'),
+  }.property('allRepositories.@each.empty-error', 'allRepoUnchecked', 'allRepositories.@each.validation'),
 
 
   /**
   /**
    * Is Repositories Accordion collapsed
    * Is Repositories Accordion collapsed
@@ -100,12 +118,6 @@ App.WizardStep1View = Em.View.extend({
    */
    */
   isRLCollapsed: true,
   isRLCollapsed: true,
 
 
-  /**
-   * Checked flags for each repo-checkbox
-   * @type {bool[]}
-   */
-  allGroupsCheckbox: [true, true, true],
-
   /**
   /**
    * Skip repo-validation
    * Skip repo-validation
    * @type {bool}
    * @type {bool}
@@ -160,118 +172,71 @@ App.WizardStep1View = Em.View.extend({
   },
   },
 
 
   /**
   /**
-   * Format repo-group values and set it to <code>allRepositoriesGroup</code>
+   * Format repo values and set it to <code>allRepositories</code>
    * @method loadRepositories
    * @method loadRepositories
    */
    */
   loadRepositories: function () {
   loadRepositories: function () {
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    var reposGroup = [
-      [],
-      [],
-      []
-    ];
-    if (App.get('supports.ubuntu')) reposGroup.push([]); // @todo: remove after Ubuntu support confirmation
-    var self = this;
+    var repos = [];
     if (selectedStack && selectedStack.operatingSystems) {
     if (selectedStack && selectedStack.operatingSystems) {
       selectedStack.operatingSystems.forEach(function (os) {
       selectedStack.operatingSystems.forEach(function (os) {
-        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 '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 'suse11':
-            cur_repo.set('osType', 'SLES 11');
-            reposGroup[2][0] = cur_repo;
-            // set group 2 properties by suse11 (any of the twe is ok)
-            self.setGroupByOs(reposGroup[2], os, 2);
-            break;
-          case 'debian12':
-            if (App.get('supports.ubuntu')) {
-              cur_repo.set('osType', 'Ubuntu 12');
-              reposGroup[3][0] = cur_repo;
-              self.setGroupByOs(reposGroup[3], os, 3);
-            }
-            break;
-        }
-      });
+        repos.push(Ember.Object.create({
+          'id': os.id,
+          'repoId': os.repoId,
+          'baseUrl': os.baseUrl,
+          'osType': os.osType,
+          'latestBaseUrl': os.latestBaseUrl,
+          'defaultBaseUrl': os.defaultBaseUrl,
+          'empty-error': !os.baseUrl,
+          'invalid-error': os.validation == 'icon-exclamation-sign',
+          'validation': os.validation,
+          'undo': os.baseUrl != os.latestBaseUrl,
+          'clearAll': os.baseUrl,
+          'errorTitle': os.errorTitle,
+          'errorContent': os.errorContent
+        }));
+      }, this);
     }
     }
-    this.set('allRepositoriesGroup', reposGroup);
+    this.set('allRepositories', repos);
   }.observes('controller.content.stacks.@each.isSelected', 'controller.content.stacks.@each.reload'),
   }.observes('controller.content.stacks.@each.isSelected', 'controller.content.stacks.@each.reload'),
 
 
-  /**
-   * Set group parameters according to operation system
-   * @method setGroupByOs
-   * @param {Ember.Object} group
-   * @param {Object} os
-   * @param {number} groupNumber
-   */
-  setGroupByOs: function (group, os, groupNumber) {
-    var isChecked = this.get('allGroupsCheckbox')[groupNumber];
-    group.set('checked', isChecked);
-    group.set('baseUrl', os.baseUrl);
-    group.set('latestBaseUrl', os.latestBaseUrl);
-    group.set('defaultBaseUrl', os.defaultBaseUrl);
-    group.set('empty-error', !os.baseUrl);
-    group.set('invalid-error', os.validation == 'icon-exclamation-sign');
-    group.set('validation', os.validation);
-    group.set('undo', os.baseUrl != os.latestBaseUrl);
-    group.set('clearAll', os.baseUrl);
-    group.set('errorTitle', os.errorTitle);
-    group.set('errorContent', os.errorContent);
-    group.set('group-number', groupNumber);
-  },
-
   /**
   /**
    * Onclick handler for checkbox of each repo group
    * Onclick handler for checkbox of each repo group
    * @method updateByCheckbox
    * @method updateByCheckbox
    */
    */
   updateByCheckbox: function () {
   updateByCheckbox: function () {
     //upload to content
     //upload to content
-    var groups = this.get('allRepositoriesGroup');
-    var self = this;
+    var repos = this.get('allRepositories');
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
+    var allRepositoriesGroups = this.get('allRepositoriesGroups');
     if (selectedStack && selectedStack.operatingSystems) {
     if (selectedStack && selectedStack.operatingSystems) {
       selectedStack.operatingSystems.forEach(function (os) {
       selectedStack.operatingSystems.forEach(function (os) {
-        var groupNumber = self.osTypeToGroup(os.osType);
-        var targetGroup = groups.findProperty('group-number', groupNumber);
-        if (!targetGroup.get('checked')) {
+        var targetRepo = repos.findProperty('id', os.id);
+        var repoGroup = allRepositoriesGroups.findProperty('name', targetRepo.get('osType'));
+        if (repoGroup && !repoGroup.get('checked')) {
           os.baseUrl = os.latestBaseUrl;
           os.baseUrl = os.latestBaseUrl;
           os.validation = null;
           os.validation = null;
           os.selected = false;
           os.selected = false;
-          targetGroup.set('baseUrl', os.latestBaseUrl);
-          targetGroup.set('latestBaseUrl', os.latestBaseUrl);
-          targetGroup.set('undo', targetGroup.get('baseUrl') != targetGroup.get('latestBaseUrl'));
-          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'));
+          targetRepo.set('baseUrl', os.latestBaseUrl);
+          targetRepo.set('latestBaseUrl', os.latestBaseUrl);
+          targetRepo.set('undo', targetRepo.get('baseUrl') != targetRepo.get('latestBaseUrl'));
+          targetRepo.set('invalid-error', false);
+          targetRepo.set('validation', null);
+          targetRepo.set('clearAll', false);
+          targetRepo.set('empty-error', !targetRepo.get('baseUrl'));
         } else {
         } else {
           os.selected = true;
           os.selected = true;
-          os.skipValidation = self.get('skipValidationChecked');
+          os.skipValidation = this.get('skipValidationChecked');
           if (os.skipValidation) {
           if (os.skipValidation) {
-            targetGroup.set('validation', null);
-            targetGroup.set('invalid-error', false);
+            targetRepo.set('validation', null);
+            targetRepo.set('invalid-error', false);
           }
           }
-          targetGroup.set('clearAll', targetGroup.get('baseUrl'));
-          targetGroup.set('empty-error', !targetGroup.get('baseUrl'));
-          self.get('allGroupsCheckbox')[groupNumber] = true;
+          targetRepo.set('clearAll', targetRepo.get('baseUrl'));
+          targetRepo.set('empty-error', !targetRepo.get('baseUrl'));
         }
         }
-      });
+      }, this);
     }
     }
-  }.observes('allRepositoriesGroup.@each.checked', 'skipValidationChecked'),
+  }.observes('allRepositoriesGroups.@each.checked', 'skipValidationChecked'),
 
 
   /**
   /**
    * Onclick handler for undo action of each repo group
    * Onclick handler for undo action of each repo group
@@ -298,69 +263,35 @@ App.WizardStep1View = Em.View.extend({
    * @param {string} newBaseUrlField
    * @param {string} newBaseUrlField
    */
    */
   doActionForGroupLocalRepository: function (event, newBaseUrlField) {
   doActionForGroupLocalRepository: function (event, newBaseUrlField) {
-    var osTypes = this.groupToOsType(event.context.get('group-number'));
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
-    osTypes.forEach(function (os) {
-      var cos = selectedStack.operatingSystems.findProperty('osType', os);
-      cos.baseUrl = Em.isEmpty(newBaseUrlField) ? '' : Em.get(cos, newBaseUrlField);
-      cos.validation = null;
-    });
+    var cos = selectedStack.operatingSystems.findProperty('id', event.context.get('id'));
+    cos.baseUrl = Em.isEmpty(newBaseUrlField) ? '' : Em.get(cos, newBaseUrlField);
+    cos.validation = null;
     this.loadRepositories();
     this.loadRepositories();
   },
   },
 
 
   /**
   /**
-   * Handler when editing any repo group BaseUrl
-   * @method editGroupLocalRepository
+   * Handler when editing any repo BaseUrl
+   * @method editLocalRepository
    */
    */
-  editGroupLocalRepository: function () {
+  editLocalRepository: function () {
     //upload to content
     //upload to content
-    var groups = this.get('allRepositoriesGroup');
-    var self = this;
+    var repos = this.get('allRepositories');
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     var selectedStack = this.get('controller.content.stacks').findProperty('isSelected', true);
     if (selectedStack && selectedStack.operatingSystems) {
     if (selectedStack && selectedStack.operatingSystems) {
       selectedStack.operatingSystems.forEach(function (os) {
       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');
+        var targetRepo = repos.findProperty('id', os.id);
+        if (os.baseUrl != targetRepo.get('baseUrl')) {
+          os.baseUrl = targetRepo.get('baseUrl');
           os.validation = null;
           os.validation = null;
-          targetGroup.set('undo', targetGroup.get('baseUrl') != targetGroup.get('latestBaseUrl'));
-          targetGroup.set('invalid-error', false);
-          targetGroup.set('validation', null);
-          targetGroup.set('clearAll', os.baseUrl);
-          targetGroup.set('empty-error', !targetGroup.get('baseUrl'));
+          targetRepo.set('undo', targetRepo.get('baseUrl') != targetRepo.get('latestBaseUrl'));
+          targetRepo.set('invalid-error', false);
+          targetRepo.set('validation', null);
+          targetRepo.set('clearAll', os.baseUrl);
+          targetRepo.set('empty-error', !targetRepo.get('baseUrl'));
         }
         }
       });
       });
     }
     }
-  }.observes('allRepositoriesGroup.@each.baseUrl'),
-
-  /**
-   * Get list of OS for provided group number
-   * @method groupToOsType
-   * @param {number} groupNumber
-   * @returns {Array}
-   */
-  groupToOsType: function (groupNumber) {
-    return Em.getWithDefault({
-      '0': ['redhat5'],
-      '1': ['redhat6'],
-      '2': ['suse11'],
-      '3': ['debian12']
-    }, groupNumber.toString(), []);
-  },
-
-  /**
-   * Get group number for provided OS
-   * @method osTypeToGroup
-   * @param {string} osType
-   * @returns {number}
-   */
-  osTypeToGroup: function (osType) {
-    return Em.getWithDefault({
-      'redhat5': 0,
-      'redhat6': 1,
-      'suse11': 2,
-      'debian12': 3
-    }, osType, -1);
-  }
+  }.observes('allRepositories.@each.baseUrl')
 
 
 });
 });

+ 214 - 320
ambari-web/test/views/wizard/step1_view_test.js

@@ -36,47 +36,67 @@ describe('App.WizardStep1View', function () {
     });
     });
   });
   });
 
 
-  describe('#osTypeToGroup', function () {
+  describe('#allRepositoriesGroups', function () {
 
 
-    var tests = Em.A([
-      {os: 'redhat5', e: 0},
-      {os: 'redhat6', e: 1},
-      {os: 'suse11', e: 2},
-      {os: 'debian12', e: 3},
-      {os: 'bulgen', e: -1}
-    ]);
-
-    tests.forEach(function (test) {
-      it(test.os, function () {
-        expect(view.osTypeToGroup(test.os)).to.equal(test.e);
-      });
+    var controller = Em.Object.create({
+      content: {
+        stacks: [
+          {
+            operatingSystems: [
+              {
+                osType: 'redhat5',
+                selected: true
+              },
+              {
+                osType: 'redhat5',
+                selected: true
+              },
+              {
+                osType: 'redhat6',
+                selected: false
+              }
+            ],
+            isSelected: true
+          }
+        ]
+      }
     });
     });
 
 
-  });
-
-  describe('#groupToOsType', function () {
-
-    var tests = Em.A([
-      {type: 0, e: ['redhat5']},
-      {type: 1, e: ['redhat6']},
-      {type: 2, e: ['suse11']},
-      {type: 3, e: ['debian12']},
-      {type: -1, e: []}
-    ]);
+    var allRepositories = [
+      Ember.Object.create({osType: 'redhat5', 'empty-error': true}),
+      Ember.Object.create({osType: 'redhat5', 'empty-error': true}),
+      Ember.Object.create({osType: 'redhat6', 'empty-error': true})
+    ];
 
 
-    tests.forEach(function (test) {
-      it(test.type, function () {
-        expect(view.groupToOsType(test.type)).to.eql(test.e);
+    it('should create repo groups from repo list', function () {
+      view.reopen({
+        controller: controller
       });
       });
+      view.set('allRepositories', allRepositories);
+      expect(view.get('allRepositoriesGroups.length')).to.equal(2);
+      expect(view.get('allRepositoriesGroups')[0].get('name')).to.equal('redhat5');
+      expect(view.get('allRepositoriesGroups')[1].get('name')).to.equal('redhat6');
+      expect(view.get('allRepositoriesGroups')[0].get('checked')).to.be.true;
+      expect(view.get('allRepositoriesGroups')[1].get('checked')).to.be.false;
+      expect(view.get('allRepositoriesGroups')[0].get('repositories')).to.eql([allRepositories[0], allRepositories[1]]);
+      expect(view.get('allRepositoriesGroups')[1].get('repositories')).to.eql([allRepositories[2]]);
     });
     });
 
 
+    it('should create empty array if there is no stacks', function () {
+      view.reopen({
+        controller: controller
+      });
+      view.set('controller.content.stacks', []);
+      view.set('allRepositories', allRepositories);
+      expect(view.get('allRepositoriesGroups.length')).to.equal(0);
+    });
   });
   });
 
 
   describe('#emptyRepoExist', function () {
   describe('#emptyRepoExist', function () {
 
 
     var tests = Em.A([
     var tests = Em.A([
       {
       {
-        allRepositoriesGroup: [
+        allRepositories: [
           {'empty-error': false},
           {'empty-error': false},
           {'empty-error': false},
           {'empty-error': false},
           {'empty-error': false}
           {'empty-error': false}
@@ -84,7 +104,7 @@ describe('App.WizardStep1View', function () {
         e: false
         e: false
       },
       },
       {
       {
-        allRepositoriesGroup: [
+        allRepositories: [
           {'empty-error': true},
           {'empty-error': true},
           {'empty-error': false},
           {'empty-error': false},
           {'empty-error': false}
           {'empty-error': false}
@@ -92,7 +112,7 @@ describe('App.WizardStep1View', function () {
         e: true
         e: true
       },
       },
       {
       {
-        allRepositoriesGroup: [
+        allRepositories: [
           {'empty-error': true},
           {'empty-error': true},
           {'empty-error': true},
           {'empty-error': true},
           {'empty-error': true}
           {'empty-error': true}
@@ -102,19 +122,18 @@ describe('App.WizardStep1View', function () {
     ]);
     ]);
 
 
     tests.forEach(function (test) {
     tests.forEach(function (test) {
-      it(test.allRepositoriesGroup.mapProperty('empty-error').join(', '), function () {
-        view.set('allRepositoriesGroup', test.allRepositoriesGroup);
+      it(test.allRepositories.mapProperty('empty-error').join(', '), function () {
+        view.set('allRepositories', test.allRepositories);
         expect(view.get('emptyRepoExist')).to.equal(test.e);
         expect(view.get('emptyRepoExist')).to.equal(test.e);
       });
       });
     });
     });
-
   });
   });
 
 
   describe('#allRepoUnchecked', function () {
   describe('#allRepoUnchecked', function () {
 
 
     var tests = Em.A([
     var tests = Em.A([
       {
       {
-        allRepositoriesGroup: [
+        allRepositoriesGroups: [
           {'checked': false},
           {'checked': false},
           {'checked': false},
           {'checked': false},
           {'checked': false}
           {'checked': false}
@@ -122,7 +141,7 @@ describe('App.WizardStep1View', function () {
         e: true
         e: true
       },
       },
       {
       {
-        allRepositoriesGroup: [
+        allRepositoriesGroups: [
           {'checked': true},
           {'checked': true},
           {'checked': false},
           {'checked': false},
           {'checked': false}
           {'checked': false}
@@ -130,7 +149,7 @@ describe('App.WizardStep1View', function () {
         e: false
         e: false
       },
       },
       {
       {
-        allRepositoriesGroup: [
+        allRepositoriesGroups: [
           {'checked': true},
           {'checked': true},
           {'checked': true},
           {'checked': true},
           {'checked': true}
           {'checked': true}
@@ -140,8 +159,10 @@ describe('App.WizardStep1View', function () {
     ]);
     ]);
 
 
     tests.forEach(function (test) {
     tests.forEach(function (test) {
-      it(test.allRepositoriesGroup.mapProperty('checked').join(', '), function () {
-        view.set('allRepositoriesGroup', test.allRepositoriesGroup);
+      it(test.allRepositoriesGroups.mapProperty('checked').join(', '), function () {
+        view.reopen({
+          allRepositoriesGroups: test.allRepositoriesGroups
+        });
         expect(view.get('allRepoUnchecked')).to.equal(test.e);
         expect(view.get('allRepoUnchecked')).to.equal(test.e);
       });
       });
     });
     });
@@ -254,33 +275,36 @@ describe('App.WizardStep1View', function () {
     var tests = Em.A([
     var tests = Em.A([
       {
       {
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 1})],
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 1})],
-        allRepositoriesGroup: [Em.Object.create({validation: 'icon-exclamation-sign'})],
+        allRepositories: [Em.Object.create({validation: 'icon-exclamation-sign'})],
         m: 'invalidCnt: 1, validation: icon-exclamation-sign',
         m: 'invalidCnt: 1, validation: icon-exclamation-sign',
         e: true
         e: true
       },
       },
       {
       {
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 1})],
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 1})],
-        allRepositoriesGroup: [Em.Object.create({validation: ''})],
+        allRepositories: [Em.Object.create({validation: ''})],
         m: 'invalidCnt: 1, validation: ""',
         m: 'invalidCnt: 1, validation: ""',
         e: false
         e: false
       },
       },
       {
       {
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 0})],
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 0})],
-        allRepositoriesGroup: [Em.Object.create({validation: ''})],
+        allRepositories: [Em.Object.create({validation: ''})],
         m: 'invalidCnt: 0, validation: ""',
         m: 'invalidCnt: 0, validation: ""',
         e: false
         e: false
       },
       },
       {
       {
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 0})],
         stacks: [Em.Object.create({isSelected: true, invalidCnt: 0})],
-        allRepositoriesGroup: [Em.Object.create({validation: 'icon-exclamation-sign'})],
+        allRepositories: [Em.Object.create({validation: 'icon-exclamation-sign'})],
         m: 'invalidCnt: 0, validation: icon-exclamation-sign',
         m: 'invalidCnt: 0, validation: icon-exclamation-sign',
         e: false
         e: false
       }
       }
     ]);
     ]);
     tests.forEach(function (test) {
     tests.forEach(function (test) {
       it(test.m, function () {
       it(test.m, function () {
+        view.reopen({
+          allRepositoriesGroups: null
+        });
         view.set('controller.content.stacks', test.stacks);
         view.set('controller.content.stacks', test.stacks);
-        view.set('allRepositoriesGroup', test.allRepositoriesGroup);
+        view.set('allRepositories', test.allRepositories);
         expect(view.get('invalidUrlExist')).to.equal(test.e);
         expect(view.get('invalidUrlExist')).to.equal(test.e);
       });
       });
     });
     });
@@ -289,47 +313,56 @@ describe('App.WizardStep1View', function () {
   describe('#totalErrorCnt', function () {
   describe('#totalErrorCnt', function () {
     var tests = Em.A([
     var tests = Em.A([
       {
       {
-        allRepositoriesGroup: [
-          {checked: false}
+        allRepositories: [
+          {}
         ],
         ],
         m: 'allRepoUnchecked',
         m: 'allRepoUnchecked',
+        allRepoUnchecked: true,
         e: 1
         e: 1
       },
       },
       {
       {
-        allRepositoriesGroup: [
-          {checked: true, 'empty-error': true},
-          {checked: false, 'empty-error': true}
+        allRepositories: [
+          {'empty-error': true},
+          {'empty-error': true}
         ],
         ],
+        allRepoUnchecked: false,
         m: 'two with empty-error',
         m: 'two with empty-error',
         e: 2
         e: 2
       },
       },
       {
       {
-        allRepositoriesGroup: [
-          {checked: true, 'validation': 'icon-exclamation-sign'},
-          {checked: false, 'validation': 'icon-exclamation-sign'}
+        allRepositories: [
+          {'validation': 'icon-exclamation-sign'},
+          {'validation': 'icon-exclamation-sign'}
         ],
         ],
+        allRepoUnchecked: false,
         m: 'two with validation="icon-exclamation-sign"',
         m: 'two with validation="icon-exclamation-sign"',
         e: 2
         e: 2
       },
       },
       {
       {
-        allRepositoriesGroup: [
-          {checked: true, 'empty-error': true, 'validation': 'icon-exclamation-sign'},
-          {checked: false, 'empty-error': true, 'validation': 'icon-exclamation-sign'}
+        allRepositories: [
+          {'empty-error': true, 'validation': 'icon-exclamation-sign'},
+          {'empty-error': true, 'validation': 'icon-exclamation-sign'}
         ],
         ],
+        allRepoUnchecked: false,
         m: 'two with empty-error, two with validation="icon-exclamation-sign"',
         m: 'two with empty-error, two with validation="icon-exclamation-sign"',
         e: 4
         e: 4
       },
       },
       {
       {
-        allRepositoriesGroup: [
-          {checked: true}
+        allRepositories: [
+          {}
         ],
         ],
+        allRepoUnchecked: false,
         m: 'no errors/warnings etc',
         m: 'no errors/warnings etc',
         e: 0
         e: 0
       }
       }
     ]);
     ]);
     tests.forEach(function (test) {
     tests.forEach(function (test) {
       it(test.m, function () {
       it(test.m, function () {
-        view.set('allRepositoriesGroup', test.allRepositoriesGroup);
+        view.reopen({
+          allRepositoriesGroups: null,
+          allRepoUnchecked: test.allRepoUnchecked
+        });
+        view.set('allRepositories', test.allRepositories);
         expect(view.get('totalErrorCnt')).to.equal(test.e);
         expect(view.get('totalErrorCnt')).to.equal(test.e);
       });
       });
     });
     });
@@ -412,160 +445,67 @@ describe('App.WizardStep1View', function () {
     });
     });
   });
   });
 
 
-  describe('#setGroupByOs', function () {
-    Em.A([
-        {
-          allGroupsCheckbox: [true, false, true],
-          groupNumber: 1,
-          m: 'should update group',
-          os: {
-            baseUrl: 'baseUrl',
-            latestBaseUrl: 'latestBaseUrl',
-            defaultBaseUrl: 'defaultBaseUrl',
-            validation: 'icon-exclamation-sign',
-            errorTitle: 'errorTitle',
-            errorContent: 'errorContent'
-          },
-          e: {
-            'checked': false,
-            'baseUrl': 'baseUrl',
-            'latestBaseUrl': 'latestBaseUrl',
-            'defaultBaseUrl': 'defaultBaseUrl',
-            'empty-error': false,
-            'invalid-error': true,
-            'validation': 'icon-exclamation-sign',
-            'undo': true,
-            'clearAll': 'baseUrl',
-            'errorTitle': 'errorTitle',
-            'errorContent': 'errorContent',
-            'group-number': 1
-          }
-        },
-        {
-          allGroupsCheckbox: [true, false, true],
-          groupNumber: 0,
-          m: 'should update group (2)',
-          os: {
-            baseUrl: '',
-            latestBaseUrl: 'latestBaseUrl',
-            defaultBaseUrl: 'defaultBaseUrl',
-            validation: 'validation',
-            errorTitle: 'errorTitle',
-            errorContent: 'errorContent'
-          },
-          e: {
-            'checked': true,
-            'baseUrl': '',
-            'latestBaseUrl': 'latestBaseUrl',
-            'defaultBaseUrl': 'defaultBaseUrl',
-            'empty-error': true,
-            'invalid-error': false,
-            'validation': 'validation',
-            'undo': true,
-            'clearAll': '',
-            'errorTitle': 'errorTitle',
-            'errorContent': 'errorContent',
-            'group-number': 0
-          }
-        },
-        {
-          allGroupsCheckbox: [true, false, true],
-          groupNumber: 0,
-          m: 'should update group (3)',
-          os: {
-            baseUrl: 'latestBaseUrl',
-            latestBaseUrl: 'latestBaseUrl',
-            defaultBaseUrl: 'defaultBaseUrl',
-            validation: 'validation',
-            errorTitle: 'errorTitle',
-            errorContent: 'errorContent'
-          },
-          e: {
-            'checked': true,
-            'baseUrl': 'latestBaseUrl',
-            'latestBaseUrl': 'latestBaseUrl',
-            'defaultBaseUrl': 'defaultBaseUrl',
-            'empty-error': false,
-            'invalid-error': false,
-            'validation': 'validation',
-            'undo': false,
-            'clearAll': 'latestBaseUrl',
-            'errorTitle': 'errorTitle',
-            'errorContent': 'errorContent',
-            'group-number': 0
-          }
-        }
-      ]).forEach(function (test) {
-        it(test.m, function () {
-          var group = Em.Object.create({});
-          view.set('allGroupsCheckbox', test.allGroupsCheckbox);
-          view.setGroupByOs(group, test.os, test.groupNumber);
-          Em.keys(test.e).forEach(function (k) {
-            expect(group.get(k)).to.equal(test.e[k]);
-          });
-        });
-      });
-  });
-
   describe('#updateByCheckbox', function () {
   describe('#updateByCheckbox', function () {
 
 
-    it('shouldn\'t do nothing if no stack selected', function () {
-      var groups = [
-        {},
-        {},
-        {}
-      ];
-      view.reopen({
-        allRepositoriesGroup: groups,
-        controller: {
-          content: {
-            stacks: [
-              {isSelected: false}
-            ]
-          }
-        }
-      });
-      view.updateByCheckbox();
-      view.get('allRepositoriesGroup').forEach(function(g) {
-        expect(g).to.eql({});
-      });
-    });
+    var allRepositories = [
+      Em.Object.create({
+        id: 'id',
+        osType: 'redhat5',
+        baseUrl: 'baseUrl',
+        latestBaseUrl: 'latestBaseUrl',
+        validation: '',
+        selected: ''
+      })
+    ];
+
+    var allRepositoriesGroups = [
+      Em.Object.create({
+        name: 'redhat5',
+        checked: false,
+        repositories: [Em.Object.create({
+          id: 'id',
+          osType: 'redhat5',
+          baseUrl: 'baseUrl',
+          latestBaseUrl: 'latestBaseUrl',
+          validation: '',
+          selected: ''
+        })
+        ]
+      })
+    ];
 
 
-    it('target group isn\'t checked', function() {
-      view.reopen({
-        allGroupsCheckbox: [true],
-        allRepositoriesGroup: [
-          Em.Object.create({
-            'group-number': 0,
-            checked: false
-          })
-        ],
-        controller: {
-          content: {
-            stacks: [
+    var controller = {
+      content: {
+        stacks: [
+          {
+            isSelected: true,
+            operatingSystems: [
               {
               {
-                isSelected: true,
-                operatingSystems: [
-                  {
-                    osType: 'redhat5',
-                    baseUrl: 'baseUrl',
-                    latestBaseUrl: 'latestBaseUrl',
-                    validation: '',
-                    selected: ''
-                  }
-                ]
+                id: 'id',
+                osType: 'redhat5',
+                baseUrl: 'baseUrl',
+                latestBaseUrl: 'latestBaseUrl',
+                validation: '',
+                selected: false
               }
               }
             ]
             ]
           }
           }
-        }
+        ]
+      }
+    };
+
+    it('target group isn\'t checked', function () {
+      view.reopen({
+        allRepositories: allRepositories,
+        allRepositoriesGroups: allRepositoriesGroups,
+        controller: controller
       });
       });
       view.updateByCheckbox();
       view.updateByCheckbox();
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
-        targetGroup = view.get('allRepositoriesGroup.firstObject');
+          targetGroup = view.get('allRepositories.firstObject');
       expect(os.baseUrl).to.equal(os.latestBaseUrl);
       expect(os.baseUrl).to.equal(os.latestBaseUrl);
       expect(os.selected).to.equal(false);
       expect(os.selected).to.equal(false);
       expect(os.validation).to.be.null;
       expect(os.validation).to.be.null;
-      expect(view.get('allGroupsCheckbox')).to.eql([false]);
       expect(targetGroup.get('baseUrl')).to.equal('latestBaseUrl');
       expect(targetGroup.get('baseUrl')).to.equal('latestBaseUrl');
       expect(targetGroup.get('latestBaseUrl')).to.equal('latestBaseUrl');
       expect(targetGroup.get('latestBaseUrl')).to.equal('latestBaseUrl');
       expect(targetGroup.get('undo')).to.equal(false);
       expect(targetGroup.get('undo')).to.equal(false);
@@ -575,52 +515,29 @@ describe('App.WizardStep1View', function () {
       expect(targetGroup.get('validation')).to.be.null;
       expect(targetGroup.get('validation')).to.be.null;
     });
     });
 
 
-    it('target group is checked, skipValidationChecked = true', function() {
+    it('target group is checked, skipValidationChecked = true', function () {
+      controller.content.stacks[0].operatingSystems[0].selected = true;
+      allRepositoriesGroups[0].set('checked', true);
       view.reopen({
       view.reopen({
-        allGroupsCheckbox: [false],
-        skipValidationChecked: true,
-        allRepositoriesGroup: [
-          Em.Object.create({
-            'group-number': 0,
-            checked: true,
-            baseUrl: ''
-          })
-        ],
-        controller: {
-          content: {
-            stacks: [
-              {
-                isSelected: true,
-                operatingSystems: [
-                  {
-                    osType: 'redhat5',
-                    baseUrl: 'baseUrl',
-                    latestBaseUrl: 'latestBaseUrl',
-                    validation: '',
-                    selected: ''
-                  }
-                ]
-              }
-            ]
-          }
-        }
+        allRepositories: allRepositories,
+        allRepositoriesGroups: allRepositoriesGroups,
+        controller: controller,
+        skipValidationChecked: true
       });
       });
       view.updateByCheckbox();
       view.updateByCheckbox();
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
-        targetGroup = view.get('allRepositoriesGroup.firstObject');
+          targetGroup = view.get('allRepositories.firstObject');
       expect(os.selected).to.equal(true);
       expect(os.selected).to.equal(true);
       expect(os.skipValidation).to.equal(true);
       expect(os.skipValidation).to.equal(true);
-      expect(view.get('allGroupsCheckbox')).to.eql([true]);
       expect(targetGroup.get('invalid-error')).to.equal(false);
       expect(targetGroup.get('invalid-error')).to.equal(false);
-      expect(targetGroup.get('empty-error')).to.equal(true);
-      expect(targetGroup.get('clearAll')).to.equal('');
+      expect(targetGroup.get('empty-error')).to.equal(false);
+      expect(targetGroup.get('clearAll')).to.equal('latestBaseUrl');
       expect(targetGroup.get('validation')).to.be.null;
       expect(targetGroup.get('validation')).to.be.null;
     });
     });
-
   });
   });
 
 
-  describe('#clearGroupLocalRepository', function() {
-    it('should be proxy for doActionForGroupLocalRepository', function() {
+  describe('#clearGroupLocalRepository', function () {
+    it('should be proxy for doActionForGroupLocalRepository', function () {
       sinon.stub(view, 'doActionForGroupLocalRepository', Em.K);
       sinon.stub(view, 'doActionForGroupLocalRepository', Em.K);
       view.clearGroupLocalRepository({});
       view.clearGroupLocalRepository({});
       expect(view.doActionForGroupLocalRepository.calledWith({}, '')).to.equal(true);
       expect(view.doActionForGroupLocalRepository.calledWith({}, '')).to.equal(true);
@@ -628,8 +545,8 @@ describe('App.WizardStep1View', function () {
     });
     });
   });
   });
 
 
-  describe('#undoGroupLocalRepository', function() {
-    it('should be proxy for doActionForGroupLocalRepository', function() {
+  describe('#undoGroupLocalRepository', function () {
+    it('should be proxy for doActionForGroupLocalRepository', function () {
       sinon.stub(view, 'doActionForGroupLocalRepository', Em.K);
       sinon.stub(view, 'doActionForGroupLocalRepository', Em.K);
       view.undoGroupLocalRepository({});
       view.undoGroupLocalRepository({});
       expect(view.doActionForGroupLocalRepository.calledWith({}, 'latestBaseUrl')).to.equal(true);
       expect(view.doActionForGroupLocalRepository.calledWith({}, 'latestBaseUrl')).to.equal(true);
@@ -637,21 +554,20 @@ describe('App.WizardStep1View', function () {
     });
     });
   });
   });
 
 
-  describe('#doActionForGroupLocalRepository', function() {
+  describe('#doActionForGroupLocalRepository', function () {
 
 
-    beforeEach(function() {
+    beforeEach(function () {
       sinon.stub(view, 'loadRepositories', Em.K);
       sinon.stub(view, 'loadRepositories', Em.K);
     });
     });
 
 
-    afterEach(function() {
+    afterEach(function () {
       view.loadRepositories.restore();
       view.loadRepositories.restore();
     });
     });
 
 
-    it('should update OS in selected stack', function() {
+    it('should update OS in selected stack', function () {
       var event = {context: Em.Object.create({'group-number': 0})};
       var event = {context: Em.Object.create({'group-number': 0})};
       view.reopen({
       view.reopen({
-        allGroupsCheckbox: [true],
-        allRepositoriesGroup: [
+        allRepositories: [
           Em.Object.create({
           Em.Object.create({
             'group-number': 0,
             'group-number': 0,
             checked: false
             checked: false
@@ -683,11 +599,10 @@ describe('App.WizardStep1View', function () {
       expect(view.loadRepositories.calledOnce).to.equal(true);
       expect(view.loadRepositories.calledOnce).to.equal(true);
     });
     });
 
 
-    it('should update OS in selected stack (2)', function() {
+    it('should update OS in selected stack (2)', function () {
       var event = {context: Em.Object.create({'group-number': 0})};
       var event = {context: Em.Object.create({'group-number': 0})};
       view.reopen({
       view.reopen({
-        allGroupsCheckbox: [true],
-        allRepositoriesGroup: [
+        allRepositories: [
           Em.Object.create({
           Em.Object.create({
             'group-number': 0,
             'group-number': 0,
             checked: false
             checked: false
@@ -721,12 +636,11 @@ describe('App.WizardStep1View', function () {
 
 
   });
   });
 
 
-  describe('#editGroupLocalRepository', function() {
+  describe('#editLocalRepository', function () {
 
 
-    it('should update os and group', function() {
+    it('should update os and group', function () {
       view.reopen({
       view.reopen({
-        allGroupsCheckbox: [true],
-        allRepositoriesGroup: [
+        allRepositories: [
           Em.Object.create({
           Em.Object.create({
             'group-number': 0,
             'group-number': 0,
             checked: false,
             checked: false,
@@ -752,9 +666,9 @@ describe('App.WizardStep1View', function () {
           }
           }
         }
         }
       });
       });
-      view.editGroupLocalRepository();
+      view.editLocalRepository();
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
       var os = view.get('controller.content.stacks')[0].operatingSystems[0],
-        targetGroup = view.get('allRepositoriesGroup.firstObject');
+          targetGroup = view.get('allRepositories.firstObject');
       expect(os.baseUrl).to.equal(targetGroup.get('baseUrl'));
       expect(os.baseUrl).to.equal(targetGroup.get('baseUrl'));
       expect(os.validation).to.be.null;
       expect(os.validation).to.be.null;
 
 
@@ -767,82 +681,62 @@ describe('App.WizardStep1View', function () {
 
 
   });
   });
 
 
-  describe('#loadRepositories', function() {
-    beforeEach(function() {
-      sinon.stub(view, 'setGroupByOs', Em.K);
+  describe('#loadRepositories', function () {
+    beforeEach(function () {
       sinon.stub(view, 'updateByCheckbox', Em.K);
       sinon.stub(view, 'updateByCheckbox', Em.K);
-      sinon.stub(view, 'editGroupLocalRepository', Em.K);
-      sinon.stub(App, 'get', function(k) {
-        if('supports.ubuntu' == k) return true;
-        return Em.get(App, k);
-      });
+      sinon.stub(view, 'editLocalRepository', Em.K);
     });
     });
-    afterEach(function() {
-      view.setGroupByOs.restore();
+    afterEach(function () {
       view.updateByCheckbox.restore();
       view.updateByCheckbox.restore();
-      view.editGroupLocalRepository.restore();
-      App.get.restore();
+      view.editLocalRepository.restore();
     });
     });
-    Em.A([
-        {
-          osType: 'redhat5',
-          e: {
-            i: 0,
-            o: 'Red Hat 5'
-          }
-        },
-        {
-          osType: 'redhat6',
-          e: {
-            i: 1,
-            o: 'Red Hat 6'
-          }
-        },
-        {
-          osType: 'suse11',
-          e: {
-            i: 2,
-            o: 'SLES 11'
-          }
-        },
-        {
-          osType: 'debian12',
-          e: {
-            i: 3,
-            o: 'Ubuntu 12'
-          }
-        }
-      ]).forEach(function (test) {
-        it(test.osType, function () {
-          view.reopen({
-            allGroupsCheckbox: [true],
-            allRepositoriesGroup: [
-              Em.Object.create({
-                'group-number': 0,
-                checked: false,
-                baseUrl: 'b1'
-              })
-            ],
-            controller: {
-              content: {
-                stacks: [
-                  {
-                    isSelected: true,
-                    operatingSystems: [
-                      {
-                        osType: test.osType,
-                        baseUrl: 'baseUrl'
-                      }
-                    ]
-                  }
-                ]
-              }
+    it('Should create repository object from controller content stack data', function () {
+      controller = {
+        content: {
+          stacks: [
+            {
+              isSelected: true,
+              operatingSystems: [
+                {
+                  'id': 'test',
+                  'repoId': 'HDP',
+                  'baseUrl': 'http://test1',
+                  'osType': 'RedHat',
+                  'latestBaseUrl': 'http://test1',
+                  'defaultBaseUrl': 'http://test3',
+                  'validation': 'icon-exclamation-sign',
+                  'errorTitle': 'test',
+                  'errorContent': 'test'
+                }
+              ]
             }
             }
-          });
-          view.loadRepositories();
-          expect(view.get('allRepositoriesGroup')[test.e.i][0].get('osType')).to.equal(test.e.o);
-        });
+          ]
+        }
+      };
+      result = Ember.Object.create({
+        'id': 'test',
+        'repoId': 'HDP',
+        'baseUrl': 'http://test1',
+        'osType': 'RedHat',
+        'latestBaseUrl': 'http://test1',
+        'defaultBaseUrl': 'http://test3',
+        'empty-error': false,
+        'invalid-error': true,
+        'validation': 'icon-exclamation-sign',
+        'undo': false,
+        'clearAll': 'http://test1',
+        'errorTitle': 'test',
+        'errorContent': 'test'
       });
       });
+      view.reopen({
+        controller: controller
+      });
+      view.loadRepositories();
+      var allRepositories = view.get('allRepositories');
+      Em.keys(allRepositories).forEach(function (key) {
+        expect(allRepositories[0].get(key)).to.equal(result.get(key));
+      });
+    });
   });
   });
 
 
 });
 });

部分文件因为文件数量过多而无法显示