You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/11/27 14:08:22 UTC

ambari git commit: AMBARI-22482 - Use case and service based mpack selection (Jason Golieb via jonathanhurley)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714-ui 4087a1179 -> 0b915f268


AMBARI-22482 - Use case and service based mpack selection (Jason Golieb via jonathanhurley)


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

Branch: refs/heads/branch-feature-AMBARI-14714-ui
Commit: 0b915f26843ee38615fec1e8f765af25769ed271
Parents: 4087a11
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Nov 27 09:08:03 2017 -0500
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Nov 27 09:08:03 2017 -0500

----------------------------------------------------------------------
 ambari-web/app/controllers/installer.js         |  24 +-
 .../wizard/downloadProducts_controller.js       |   8 +-
 .../wizard/selectMpacks_controller.js           | 328 ++++++++++--
 ambari-web/app/messages.js                      |  20 +-
 ambari-web/app/routes/installer.js              |   1 +
 .../app/templates/wizard/selectMpacks.hbs       |  71 ++-
 .../app/templates/wizard/selectMpacks/mpack.hbs |  16 +-
 .../selectMpacks/selectedMpackVersion.hbs       |  18 +-
 .../templates/wizard/selectMpacks/service.hbs   |  34 ++
 .../templates/wizard/selectMpacks/usecase.hbs   |  28 +
 ambari-web/app/utils/ajax/ajax.js               |  41 +-
 .../app/views/wizard/selectMpacks_view.js       | 103 +++-
 .../controllers/wizard/selectMpacks_test.js     | 526 ++++++++++++++++++-
 13 files changed, 1115 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/controllers/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js
index 14ae790..59571e7 100644
--- a/ambari-web/app/controllers/installer.js
+++ b/ambari-web/app/controllers/installer.js
@@ -82,6 +82,7 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
     controllerName: 'installerController',
     mpacks: [],
     mpackVersions: [],
+    mpackServiceVersions: [],
     mpackServices: [],
     // Tracks which steps have been saved before.
     // If you revisit a step, we will know if the step has been saved previously and we can warn about making changes.
@@ -222,9 +223,15 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
     App.stackMapper.map(versionDefinition);
   },
 
-  //TODO: report error in UI
   loadMpackStackInfoError: function(request, status, error) {
-    console.log(`Failed to load stack info. ${status} - ${error}`);
+    const message = Em.I18n.t('installer.error.mpackStackInfo');
+
+    App.showAlertPopup(
+      Em.I18n.t('common.error'), //header
+      message //body
+    );
+
+    console.log(`${message} ${status} - ${error}`);
   },
 
   /**
@@ -239,7 +246,7 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
       name: 'wizard.mpack_service_components',
       sender: this,
       data: {
-        stackName: stackName || "HDP", //TODO: mpacks - Remove default when this value is provided API
+        stackName: stackName,
         stackVersion: stackVersion,
         serviceName: serviceName
       },
@@ -253,9 +260,15 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
     App.MpackServiceMapper.map(serviceInfo);
   },
 
-  //TODO: report error in UI
   loadMpackServiceInfoError: function(request, status, error) {
-    console.log(`Failed to load mpack service info. ${status} - ${error}`);
+    const message = Em.I18n.t('installer.error.mpackServiceInfo');
+
+    App.showAlertPopup(
+      Em.I18n.t('common.error'), //header
+      message //body
+    );
+    
+    console.log(`${message} ${status} - ${error}`);
   },
 
   /**
@@ -1059,6 +1072,7 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
         callback: function () {
           this.load('selectedServices');
           this.load('selectedMpacks');
+          this.load('advancedMode');
         }
       }
     ],

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/controllers/wizard/downloadProducts_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/downloadProducts_controller.js b/ambari-web/app/controllers/wizard/downloadProducts_controller.js
index b353732..d12ae11 100644
--- a/ambari-web/app/controllers/wizard/downloadProducts_controller.js
+++ b/ambari-web/app/controllers/wizard/downloadProducts_controller.js
@@ -29,7 +29,7 @@ App.WizardDownloadProductsController = Em.Controller.extend({
     selectedMpacks.forEach(mpack => {
       this.get('mpacks').pushObject(Em.Object.create({
         name: mpack.name,
-        displayName: mpack.displayName || mpack.name, //TODO: remove default when displayName is available
+        displayName: mpack.displayName,
         url: mpack.url,
         inProgress: true,
         failed: false,
@@ -101,16 +101,16 @@ App.WizardDownloadProductsController = Em.Controller.extend({
     }
 
     if (!this.get('isSubmitDisabled')) {
-      //TODO: mpacks
       //get info about stacks from version definitions and save to Stack model
       this.getRegisteredMpacks().then(mpacks => {
         const stackVersionsRegistered = mpacks.items.map(mpack => this.get('wizardController').createMpackStackVersion
           (
-            mpack.MpackInfo.stack_name || "HDP", //TODO: mpacks - remove fallback when stack info is included in API response
-            mpack.MpackInfo.stack_version || "3.0.0" //TODO: mpacks - remove fallback when stack info is included in API response
+            mpack.version[0].Versions.stack_name,
+            mpack.version[0].Versions.stack_version
           )
         );
 
+        //TODO: mpacks
         //var versionData = installerController.getSelectedRepoVersionData(); //This would be used to post a VDF xml for a local repo (I think), but do we still need to do this when we will just be using mpacks?
         $.when(...stackVersionsRegistered).always(() => { //this uses always() because the api call made by createMpackStackVersion will return a 500 error
                                                           //if the stack version has already been registered, but we want to proceed anyway

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/controllers/wizard/selectMpacks_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/selectMpacks_controller.js b/ambari-web/app/controllers/wizard/selectMpacks_controller.js
index a7c62ff..7951d15 100644
--- a/ambari-web/app/controllers/wizard/selectMpacks_controller.js
+++ b/ambari-web/app/controllers/wizard/selectMpacks_controller.js
@@ -22,9 +22,11 @@ App.WizardSelectMpacksController = Em.Controller.extend({
 
   name: 'wizardSelectMpacksController',
 
+  noRecommendationAvailable: false,
+
   loadRegistry: function () {
     return App.ajax.send({
-      name: 'registry.mpacks.versions',
+      name: 'registry.all',
       showLoadingPopup: true,
       sender: this
     });
@@ -36,6 +38,7 @@ App.WizardSelectMpacksController = Em.Controller.extend({
         registry.mpacks.map(mpack => {
           return Em.Object.create({
             name: mpack.RegistryMpackInfo.mpack_name,
+            displayName: mpack.RegistryMpackInfo.mpack_display_name,
             description: mpack.RegistryMpackInfo.mpack_description,
             logoUrl: mpack.RegistryMpackInfo.mpack_logo_url,
             versions: mpack.versions ? mpack.versions.map((version, index) => {
@@ -46,13 +49,15 @@ App.WizardSelectMpacksController = Em.Controller.extend({
                 version: version.RegistryMpackVersionInfo.mpack_version,
                 docUrl: version.RegistryMpackVersionInfo.mpack_dock_url,
                 mpackUrl: version.RegistryMpackVersionInfo.mpack_url,
-                stackName: version.RegistryMpackVersionInfo.stack_name || "HDP", //TODO: remove default when stack_name is available
-                stackVersion: version.RegistryMpackVersionInfo.stack_version || "3.0.0", //TODO: remove default when stack_version is available
+                stackName: version.RegistryMpackVersionInfo.stack_name,
+                stackVersion: version.RegistryMpackVersionInfo.stack_version,
                 services: version.RegistryMpackVersionInfo.services ? version.RegistryMpackVersionInfo.services.map(service => {
                   return Em.Object.create({
                     selected: false,
+                    displayed: index === 0 ? true : false, //by default, display first version
                     id: mpack.RegistryMpackInfo.mpack_name + version.RegistryMpackVersionInfo.mpack_version + service.name,
                     name: service.name,
+                    displayName: service.displayName || service.name, //TODO: mpacks - remove fallback when display name is available
                     version: service.version
                   })
                 }) : []
@@ -60,30 +65,101 @@ App.WizardSelectMpacksController = Em.Controller.extend({
             }) : []
           })
         })
-      ),
-    []);
+      ), []
+    );
 
     const mpackVersions = mpacks.reduce(
       (versions, mpack) => versions.concat(
-        mpack.versions.map(version => {
-          version.mpack = mpack;
+        mpack.get('versions').map(version => {
+          version.set('mpack', mpack);
           return version;
         })
       ),
-    []);
+      []);
 
-    const mpackServices = mpackVersions.reduce(
+    const mpackServiceVersions = mpackVersions.reduce(
       (services, mpackVersion) => services.concat(
-        mpackVersion.services.map(service => {
-          service.mpackVersion = mpackVersion;
+        mpackVersion.get('services').map(service => {
+          service.set('mpackVersion', mpackVersion);
           return service;
         })
       ),
-    []);
+      []);
+
+    const uniqueServices = {};
+    mpackServiceVersions.forEach(service => {
+      uniqueServices[service.name] = Em.Object.create({
+        name: service.name,
+        displayName: service.displayName,
+        description: service.description,
+        displayedVersion: function () {
+          return this.get('versions').filterProperty('displayed')[0];
+        }.property('versions.@each.displayed')
+      })
+    });
+    
+    const mpackServices = [];
+    for (let serviceName in uniqueServices) {
+      const service = uniqueServices[serviceName];
+      const versions = mpackServiceVersions.filter(serviceVersion => serviceVersion.get('name') === service.name).map(serviceVersion => {
+        serviceVersion.set('service', service);
+        return serviceVersion;
+      })
 
+      service.set('versions', versions);
+      mpackServices.push(service);
+    }
+    
     this.set('content.mpacks', mpacks);
     this.set('content.mpackVersions', mpackVersions);
+    this.set('content.mpackServiceVersions', mpackServiceVersions);
     this.set('content.mpackServices', mpackServices);
+
+    const usecases = data.items.reduce(
+      (usecases, registry) => usecases.concat(
+        registry.scenarios.map(usecase => {
+          return Em.Object.create({
+            selected: false,
+            id: usecase.RegistryScenarioInfo.scenario_id || usecase.RegistryScenarioInfo.scenario_name, //TODO: mpacks - remove fallback when id is available
+            name: usecase.RegistryScenarioInfo.scenario_name,
+            displayName: usecase.RegistryScenarioInfo.scenario_display_name || usecase.RegistryScenarioInfo.scenario_name, //TODO: mpacks - remove fallback when display name is available
+            description: usecase.RegistryScenarioInfo.scenario_description,
+            mpacks: this.getMpacksByName(usecase.RegistryScenarioInfo.scenario_mpacks.map(mpack => mpack.name))
+          });
+        })
+      ), []
+    );
+
+    this.set('content.mpackUsecases', usecases);
+  },
+  
+  getMpacksByName: function (mpackNames) {
+    return mpackNames.map(mpackName => this.getMpackByName(mpackName));
+  },
+
+  /**
+   * Returns the first (newest) version of the mpack with name matching mpackName.
+   * 
+   * @param {string} mpackName 
+   * @returns mpackVersion
+   */
+  getMpackByName: function (mpackName) {
+    const mpacks = this.get('content.mpacks');
+
+    if (mpacks) {
+      //TODO: mpacks - reinstate this if/when the test runner can handle it
+      //for (let mpack of mpacks) {
+      //if (mpack.get('name') === mpackName) {
+      //  return mpack.get('versions')[0]; //TODO: mpacks - change this to the last item when sort order is fixed
+      //}
+      for (let i = 0, length = mpacks.length; i < length; i++) {      
+        if (mpacks[i].get('name') === mpackName) {
+          return mpacks[i].get('versions')[0]; //TODO: mpacks - change this to the last item when sort order is fixed
+        }
+      }
+    }
+    
+    return null;
   },
 
   isSaved: function () {
@@ -103,16 +179,29 @@ App.WizardSelectMpacksController = Em.Controller.extend({
     );
   },
 
-  getRegistry: function () {
-    const deferred = $.Deferred();
-
+  registryLoaded() {
     const mpacks = this.get('content.mpacks');
     const mpackVersions = this.get('content.mpackVersions');
     const mpackServices = this.get('content.mpackServices');
+    const mpackServiceVersions = this.get('content.mpackServiceVersions');
+    const mpackUsecases = this.get('content.mpackUsecases');
+
+    if (!mpacks || mpacks.length === 0
+      || !mpackVersions || mpackVersions.length === 0
+      || !mpackServices || mpackServices.length === 0
+      || !mpackServiceVersions || mpackServiceVersions.length === 0) {
+      return false;
+    }
 
-    if (!mpacks || mpacks.length === 0 || !mpackVersions || mpackVersions.length === 0 || !mpackServices || mpackServices.length === 0) {
-      this.loadRegistry().then(registry => {
-        this.loadRegistrySucceeded(registry);
+    return true;
+  },
+
+  getRegistry: function () {
+    const deferred = $.Deferred();
+
+    if (!this.registryLoaded()) {
+      this.loadRegistry().then(data => {
+        this.loadRegistrySucceeded(data);
         deferred.resolve();
       },
       () => {
@@ -126,6 +215,18 @@ App.WizardSelectMpacksController = Em.Controller.extend({
     return deferred.promise();
   },
 
+  toggleMode: function () {
+    const isAdvancedMode = this.get('content.advancedMode');
+    
+    if (isAdvancedMode) { //toggling to Basic Mode
+      this.clearSelection();
+    } else { //toggling to Advanced Mode
+      this.set('noRecommendationAvailable', false);
+    }
+    
+    this.set('content.advancedMode', !isAdvancedMode);
+  },
+
   loadStep: function () {
     this.getRegistry().then(() => {
       //add previously selected services
@@ -139,22 +240,44 @@ App.WizardSelectMpacksController = Em.Controller.extend({
   },
 
   isSubmitDisabled: function () {
-    const mpackServices = this.get('content.mpackServices');
-    return mpackServices.filterProperty('selected', true).length === 0 || App.get('router.btnClickInProgress');
-  }.property('content.mpackServices.@each.selected', 'App.router.btnClickInProgress'),
-
-  getServiceById: function (serviceId) {
-    const mpackServices = this.get('content.mpackServices');
-    const byServiceId = service => service.id === serviceId;
-    const service = mpackServices.find(byServiceId);
-    return service;
-  },
+    const mpackServiceVersions = this.get('content.mpackServiceVersions');
+    return mpackServiceVersions.filterProperty('selected', true).length === 0 || App.get('router.btnClickInProgress');
+  }.property('content.mpackServiceVersions.@each.selected', 'App.router.btnClickInProgress'),
 
   getMpackVersionById: function (versionId) {
     const mpackVersions = this.get('content.mpackVersions');
     const byVersionId = version => version.id === versionId;
-    const version = mpackVersions.find(byVersionId);
-    return version;
+    
+    if (mpackVersions) {
+      const version = mpackVersions.find(byVersionId);
+      return version;
+    }  
+
+    return null;
+  },
+
+  getServiceVersionById: function (versionId) {
+    const serviceVersions = this.get('content.mpackServiceVersions');
+    const byVersionId = version => version.id === versionId;
+
+    if (serviceVersions) {
+      const version = serviceVersions.find(byVersionId);
+      return version;
+    }
+
+    return null;
+  },
+
+  getUsecaseById: function (usecaseId) {
+    const usecases = this.get('content.mpackUsecases');
+    const byUsecaseId = usecase => usecase.id === usecaseId;
+    
+    if (usecases) {
+      const usecase = usecases.find(byUsecaseId);
+      return usecase;
+    }
+    
+    return null;
   },
 
   displayMpackVersion: function (versionId) {
@@ -171,6 +294,106 @@ App.WizardSelectMpacksController = Em.Controller.extend({
     }
   },
 
+  displayServiceVersion: function (versionId) {
+    const version = this.getServiceVersionById(versionId);
+
+    if (version) {
+      version.service.versions.forEach(serviceVersion => {
+        if (serviceVersion.get('id') === versionId) {
+          serviceVersion.set('displayed', true);
+        } else {
+          serviceVersion.set('displayed', false);
+        }
+      })
+    }
+  },
+
+  addMpackHandler: function (mpackVersionId) {
+    if (this.addMpack(mpackVersionId)) {
+      this.get('wizardController').setStepUnsaved('selectMpacks');
+    }
+  },
+
+  addMpack: function (mpackVersionId) {
+    const mpackVersion = this.getMpackVersionById(mpackVersionId);
+
+    if (mpackVersion) {
+      mpackVersion.services.forEach(service => this.addService(service.id))
+      return true;
+    }
+
+    return false;
+  },
+
+  toggleUsecaseHandler: function (usecaseId) {
+    if (this.toggleUsecase(usecaseId)) {
+      this.get('wizardController').setStepUnsaved('selectMpacks');
+    }
+  },
+
+  toggleUsecase: function (usecaseId) {
+    this.clearSelection();
+    
+    const usecase = this.getUsecaseById(usecaseId);
+    if (usecase) {
+      const selected = usecase.get('selected');
+      usecase.set('selected', !selected);
+      
+      const usecasesSelected = this.get('content.mpackUsecases').filterProperty('selected');
+      if (usecasesSelected.length > 0) {
+        this.getUsecaseRecommendation()
+          .done(this.getUsecaseRecommendationSucceeded.bind(this))
+          .fail(this.getUsecaseRecommendationFailed.bind(this));
+      }
+      
+      return true;
+    }
+
+    return false;
+  },
+
+  getUsecaseRecommendation: function (registryId) {
+    const usecases = this.get('content.mpackUsecases').filterProperty('selected').map(usecase =>
+      ({
+        scenario_name: usecase.name
+      })
+    );
+
+    return App.ajax.send({
+      name: 'registry.recommendation.usecases',
+      data: {
+        registryId: registryId || 1,
+        usecases: usecases
+      },
+      showLoadingPopup: true,
+      sender: this
+    });
+  },
+
+  getUsecaseRecommendationSucceeded: function (data) {
+    this.clearSelection();
+    
+    let recommendations;
+    if (data && data.resources && data.resources.length > 0 && data.resources[0].recommendations) {
+      recommendations = data.resources[0].recommendations.mpack_bundles;
+    }
+    
+    if (recommendations && recommendations.length > 0
+      && recommendations[0].mpacks && recommendations[0].mpacks.length > 0) {
+      const mpackVersionIds = recommendations[0].mpacks.map(mpack => mpack.mpack_name + mpack.mpack_version);
+      mpackVersionIds.forEach(this.addMpack.bind(this));
+    } else {
+      this.set('noRecommendationAvailable', true);
+    }
+  },
+
+  getUsecaseRecommendationFailed: function () {
+    App.showAlertPopup(
+      Em.I18n.t('common.error'), //header
+      Em.I18n.t('installer.selectMpacks.getRecommendationFailed') //body
+    );
+  },
+
   addServiceHandler: function (serviceId) {
     if (this.addService(serviceId)) {
       this.get('wizardController').setStepUnsaved('selectMpacks');
@@ -178,7 +401,7 @@ App.WizardSelectMpacksController = Em.Controller.extend({
   },
 
   addService: function (serviceId) {
-    const service = this.getServiceById(serviceId);
+    const service = this.getServiceVersionById(serviceId);
 
     if (service) {
       service.set('selected', true);
@@ -196,7 +419,7 @@ App.WizardSelectMpacksController = Em.Controller.extend({
   },
 
   removeService: function (serviceId) {
-    const service = this.getServiceById(serviceId);
+    const service = this.getServiceVersionById(serviceId);
 
     if (service) {
       service.set('selected', false);
@@ -207,10 +430,27 @@ App.WizardSelectMpacksController = Em.Controller.extend({
     return false;
   },
 
+  removeMpackHandler: function (mpackId) {
+    if (this.removeMpack(mpackId)) {
+      this.get('wizardController').setStepUnsaved('selectMpacks');
+    }
+  },
+
+  removeMpack: function (mpackId) {
+    const mpackVersion = this.getMpackVersionById(mpackId);
+
+    if (mpackVersion) {
+      mpackVersion.get('services').forEach(service => this.removeService(service.get('id')));
+      return true;
+    }
+
+    return false;
+  },
+
   selectedServices: function () {
-    const mpackServices = this.get('content.mpackServices');
-    return mpackServices ? mpackServices.filter(s => s.get('selected') === true) : [];
-  }.property('content.mpackServices.@each.selected'),
+    const mpackServiceVersions = this.get('content.mpackServiceVersions');
+    return mpackServiceVersions ? mpackServiceVersions.filter(s => s.get('selected') === true) : [];
+  }.property('content.mpackServiceVersions.@each.selected'),
 
   selectedMpackVersions: function () {
     const versions = this.get('content.mpackVersions');
@@ -223,15 +463,25 @@ App.WizardSelectMpacksController = Em.Controller.extend({
   }.property('content.mpackVersions.@each.selected', 'selectedServices'),
 
   clearSelection: function () {
-    const mpackServices = this.get('content.mpackServices');
-    if (mpackServices) {
-      mpackServices.setEach('selected', false);
+    const mpackServiceVersions = this.get('content.mpackServiceVersions');
+    if (mpackServiceVersions) {
+      mpackServiceVersions.setEach('selected', false);
     }
-
+    
     const versions = this.get('content.mpackVersions');
     if (versions) {
       versions.setEach('selected', false);
     }
+    
+    if (this.get('content.advancedMode')) {
+      const usecases = this.get('content.mpackUsecases');
+      if (usecases) {
+        usecases.setEach('selected', false);
+      }
+    }  
+
+    this.set('noRecommendationAvailable', false);
+    this.get('wizardController').setStepUnsaved('selectMpacks');
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index c9bae25..e014d4a 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -591,6 +591,9 @@ Em.I18n.translations = {
   'installer.slaveComponentHosts.selectHosts':'select hosts for this group',
   'installer.slaveComponentHostsPopup.header':'Select which hosts should belong to which {0} group',
 
+  'installer.error.mpackServiceInfo': 'Failed to load mpack service info.',
+  'installer.error.mpackStackInfo': 'Failed to load stack info.',
+    
   'installer.controls.slaveComponentGroups':' Groups',
   'installer.controls.serviceConfigPopover.title':'{0}<br><small>{1}</small>',
   'installer.controls.checkConnection.popover':'This action will check accessibility of {0} host and port from Ambari Server host',
@@ -599,13 +602,24 @@ Em.I18n.translations = {
   'installer.controls.serviceConfigMasterHosts.header':'{0} Hosts',
   'installer.controls.slaveComponentChangeGroupName.error':'group with this name already exist',
 
-  'installer.selectMpacks.loadRegistryFailed': 'Could not load Management Packs. The software registry may not be available.',
+  'installer.selectMpacks.loadRegistryFailed': 'Could not load available management packs. The software registry may not be available.',
   'installer.selectMpacks.header': 'Select Management Packs',
   'installer.selectMpacks.body.header': 'Select Management Packs',
+  'installer.selectMpacks.noUsecasesAvailable': 'No use cases are available.',
   'installer.selectMpacks.noMpacksAvailable': 'No management packs are available.',
-  'installer.selectMpacks.noMpacksSelected': 'No Management Packs selected',
-  'installer.selectMpacks.body.options.header': 'Management Packs',
+  'installer.selectMpacks.noServicesAvailable': 'No services are available.',
+  'installer.selectMpacks.noMpacksSelected': 'No management packs selected.',
+  'installer.selectMpacks.noRecommendationAvailable': 'No management packs support the selected use cases. Please change your selection.',
+  'installer.selectMpacks.getRecommendationFailed': 'Could not load management macks supporting the selected use cases. The software registry may not be available.',
+  'installer.selectMpacks.body.header.useCases': 'Use Cases',
+  'installer.selectMpacks.body.header.mpacks': 'Management Packs',
+  'installer.selectMpacks.body.header.services': 'Services',
   'installer.selectMpacks.body.selected.header': 'Selected Management Packs',
+  'installer.selectMpacks.basicMode': 'Basic Mode',
+  'installer.selectMpacks.advancedMode': 'Advanced Mode',
+  'installer.selectMpacks.changeMode': 'Change Selection Mode',
+  'installer.selectMpacks.basicModeMessage': 'Advanced Mode allows you to directly select individual management packs and services. If you proceed to Advanced Mode, you will not be able to return to Basic Mode without losing all of your selections. Choose a selection mode.',
+  'installer.selectMpacks.advancedModeMessage': 'Basic Mode provides common use cases you can choose from that will automatically select appropriate management packs and services. You cannot change these selections directly. If you proceed to Basic Mode, you will lose all current selections. Choose a selection mode.',
 
   'installer.step0.header':'Get Started',
   'installer.step0.body.header':'Get Started',

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/routes/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js
index 9a49c36..73c716b 100644
--- a/ambari-web/app/routes/installer.js
+++ b/ambari-web/app/routes/installer.js
@@ -335,6 +335,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
         controller.save('selectedServiceNames');
         controller.save('selectedServices');
         controller.save('selectedMpacks');
+        controller.save('advancedMode');
         var wizardStep6Controller = router.get('wizardStep6Controller');
         // Clear subsequent settings if user changed service selections
         if (!wizardStep6Controller.get('isSaved')) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/templates/wizard/selectMpacks.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/selectMpacks.hbs b/ambari-web/app/templates/wizard/selectMpacks.hbs
index 19855d3..d78861e 100644
--- a/ambari-web/app/templates/wizard/selectMpacks.hbs
+++ b/ambari-web/app/templates/wizard/selectMpacks.hbs
@@ -24,18 +24,67 @@
   <!-- Registry -->
   <div class="panel panel-default col-md-8">
     <div class="panel-heading">
-      <p>{{t installer.selectMpacks.body.options.header}}</p>
-    </div>
-    <div class="panel-body">
-      <div class="options-list">
-        {{#if controller.content.mpacks}}
-          {{#each mpack in controller.content.mpacks}}
-            {{view App.WizardMpackView mpackBinding="mpack"}}
-          {{/each}}
+      {{#if controller.content.advancedMode}}
+      <ul class="nav nav-tabs" role="tablist">
+        <li role="presentation" class="active">
+          <a href="#mpacks" aria-controls="profile" role="tab" data-toggle="tab">{{t installer.selectMpacks.body.header.mpacks}}</a>
+        </li>
+        <li role="presentation">
+          <a href="#services" aria-controls="messages" role="tab" data-toggle="tab">{{t installer.selectMpacks.body.header.services}}</a>
+        </li>
+      </ul>
+      {{else}}
+      <ul class="nav nav-tabs" role="tablist">
+        <li role="presentation" class="active">
+          <a href="#usecases" aria-controls="home" role="tab" data-toggle="tab">{{t installer.selectMpacks.body.header.useCases}}</a>
+        </li>
+      </ul>
+      {{/if}}
+      <button class="btn btn-default pull-right" {{action toggleMode target="view"}}>
+        {{#if controller.content.advancedMode}}
+        {{t installer.selectMpacks.basicMode}}
         {{else}}
-          {{t installer.selectMpacks.noMpacksAvailable}}
+        {{t installer.selectMpacks.advancedMode}}
         {{/if}}
+      </button>
+    </div>
+    <div class="panel-body tab-content">
+      {{#if controller.content.advancedMode}}
+      <div role="tabpanel" class="tab-pane active" id="mpacks">
+        <div class="options-list">
+          {{#if controller.content.mpacks}}
+            {{#each mpack in controller.content.mpacks}}
+              {{view App.WizardMpackView mpackBinding="mpack"}}
+            {{/each}}
+          {{else}}
+            {{t installer.selectMpacks.noMpacksAvailable}}
+          {{/if}}
+        </div>
+      </div>
+      <div role="tabpanel" class="tab-pane" id="services">
+        <div class="options-list">
+          {{#if controller.content.mpackServices}} 
+            {{#each service in controller.content.mpackServices}}
+              {{view App.WizardServiceView serviceBinding="service"}}
+            {{/each}}
+          {{else}}
+            {{t installer.selectMpacks.noServicesAvailable}}
+          {{/if}}
+        </div>
+      </div>
+      {{else}}
+      <div role="tabpanel" class="tab-pane active" id="usecases">
+        <div class="options-list">
+          {{#if controller.content.mpackUsecases}} 
+            {{#each usecase in controller.content.mpackUsecases}}
+              {{view App.WizardUsecaseView usecaseBinding="usecase"}}
+            {{/each}}
+          {{else}}
+            {{t installer.selectMpacks.noUsecasesAvailable}}
+          {{/if}}
+        </div>
       </div>
+      {{/if}}
     </div>
   </div>
   <!-- Selection -->
@@ -48,7 +97,11 @@
         {{view App.WizardSelectedMpackVersionView mpackVersionBinding="mpackVersion"}}
       {{/each}}
     {{else}}
+      {{#if controller.noRecommendationAvailable}}
+      <div class="empty-selection">{{t installer.selectMpacks.noRecommendationAvailable}}</div>
+      {{else}}
       <div class="empty-selection">{{t installer.selectMpacks.noMpacksSelected}}</div>
+      {{/if}}
     {{/if}}
   </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs b/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs
index 9a65baf..e2bed32 100644
--- a/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs
+++ b/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs
@@ -17,8 +17,8 @@
 }}
 <div class="mpack-body">
   <div class="mpack-title" role="tab" id="headingOne">
-    {{mpack.name}} 
-    <select {{action "changeVersion" on="change" target="view"}}>
+    {{mpack.displayName}} 
+    <select {{action changeVersion on="change" target="view"}}>
       {{#each ver in mpack.versions}}
       <option {{bindAttr value="ver.id" selected="ver.displayed"}}>{{ver.version}}</option>
       {{/each}}
@@ -27,10 +27,16 @@
   <div>{{mpack.description}}</div>
   <div>
   {{#each service in view.services}}
-    <button {{bindAttr id="service.name"}} class="capsule" {{action "addService" service.id target="view"}}>
-      {{service.name}}&nbsp;{{service.version}}&nbsp;<i class="icon icon-plus"></i>
-      <span {{bindAttr class="selected:service-remove:service-add"}} {{bindAttr title="service.version"}}></span>
+    {{#if service.selected}}
+    <button class="capsule capsule-selected">
+      {{service.name}}&nbsp;{{service.version}}&nbsp;<span class="glyphicon glyphicon-ok"></span>
     </button>
+    {{else}}
+    <button class="capsule" {{action addService service.id target="view"}}>
+      {{service.name}}&nbsp;{{service.version}}&nbsp;<span class="glyphicon glyphicon-plus"></span>
+    </button>
+    {{/if}}
   {{/each}}
   </div>
+  <button class="mpack-add-button" {{action addMpack target="view"}}><span class="glyphicon glyphicon-plus"></span></button>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs b/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs
index 05e75ff..30370a9 100644
--- a/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs
+++ b/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs
@@ -17,15 +17,23 @@
 }}
 <div class="mpack-body">
   <div class="mpack-title" role="tab" id="headingOne">
-    <p>{{mpackVersion.mpack.name}} {{mpackVersion.version}}</p>
+    <p>{{mpackVersion.mpack.displayName}} {{mpackVersion.version}}</p>
+     {{#if controller.content.advancedMode}}
+     <button class="mpack-remove-button" {{action removeMpack mpackVersion.id target="view"}}><span class="glyphicon glyphicon-remove"></span></button>
+     {{/if}}
   </div>
   <div>
   {{#each service in mpackVersion.services}}
     {{#if service.selected}}
-      <button {{bindAttr id="service.name"}} class="capsule" {{action "removeService" service.id target="view"}}>
-        {{service.name}}&nbsp;<i class="icon">&times;</i>
-      <span {{bindAttr class="selected:service-remove:service-add" title="service.version"}}></span>
-    </button>
+      {{#if controller.content.advancedMode}}
+      <button class="capsule capsule-selected" {{action removeService service.id target="view"}}>
+        {{service.name}}&nbsp;{{service.version}}&nbsp;<span class="glyphicon glyphicon-remove"></span>
+      </button>
+      {{else}}
+      <button class="capsule capsule-selected">
+        {{service.name}}&nbsp;{{service.version}}
+      </button>
+      {{/if}}
     {{/if}}
   {{/each}}
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/templates/wizard/selectMpacks/service.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/selectMpacks/service.hbs b/ambari-web/app/templates/wizard/selectMpacks/service.hbs
new file mode 100644
index 0000000..b9107b7
--- /dev/null
+++ b/ambari-web/app/templates/wizard/selectMpacks/service.hbs
@@ -0,0 +1,34 @@
+{{!
+* 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.
+}}
+<div class="mpack-body">
+  <div class="mpack-title" role="tab" id="headingOne">
+    {{service.displayName}} 
+    <select {{action changeVersion on="change" target="view"}}>
+      {{#each ver in service.versions}}
+      <option {{bindAttr value="ver.id" selected="ver.displayed"}}>{{ver.version}}</option>
+      {{/each}}
+    </select>
+  </div>
+  <div>{{service.displayedVersion.mpackVersion.mpack.displayName}}&nbsp;{{service.displayedVersion.mpackVersion.version}}</div>
+  <div>{{service.description}}</div>
+  {{#if service.displayedVersion.selected}}
+  <button class="mpack-add-button checked"><span class="glyphicon glyphicon-ok"></span></button>
+  {{else}}
+  <button class="mpack-add-button" {{action add target="view"}}><span class="glyphicon glyphicon-plus"></span></button>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/templates/wizard/selectMpacks/usecase.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/selectMpacks/usecase.hbs b/ambari-web/app/templates/wizard/selectMpacks/usecase.hbs
new file mode 100644
index 0000000..de2caf7
--- /dev/null
+++ b/ambari-web/app/templates/wizard/selectMpacks/usecase.hbs
@@ -0,0 +1,28 @@
+{{!
+* 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.
+}}
+<div class="mpack-body">
+  <div class="mpack-title" role="tab" id="headingOne">
+    {{usecase.displayName}}&nbsp;<span class="glyphicon glyphicon-question-sign"></span>
+  </div>
+  <div>{{usecase.description}}</div>
+  {{#if usecase.selected}}
+  <button class="mpack-add-button checked" {{action toggle target="view"}}><span class="glyphicon glyphicon-ok"></span></button>
+  {{else}}
+  <button class="mpack-add-button" {{action toggle target="view"}}><span class="glyphicon glyphicon-plus"></span></button>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index f86fd3d..7925077 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -3069,8 +3069,8 @@ var urls = {
 
   /** Mpack related APIs */
   'mpack.download_by_url': {
-    'real': '/mpacks',
-    'format': function (data) {
+    real: '/mpacks',
+    format: function (data) {
       return {
         type: 'POST',
         data: JSON.stringify({
@@ -3085,8 +3085,8 @@ var urls = {
   },
 
   'mpack.download': {
-    'real': '/mpacks',
-    'format': function (data) {
+    real: '/mpacks',
+    format: function (data) {
       return {
         type: 'POST',
         data: JSON.stringify({
@@ -3103,12 +3103,12 @@ var urls = {
   },
 
   'mpack.get_registered_mpacks': {
-    'real': '/mpacks',
+    real: '/mpacks?fields=*',
   },
 
   'mpack.create_version_definition': {
-    'real': '/version_definitions',
-    'format': function (data) {
+    real: '/version_definitions',
+    format: function (data) {
       return {
         type: 'POST',
         data: JSON.stringify({
@@ -3123,34 +3123,45 @@ var urls = {
   },
 
   'mpack.get_version_definition': {
-    'real': '/version_definitions/{id}?fields=VersionDefinition/*,operating_systems/repositories/Repositories/*,operating_systems/OperatingSystems/*,VersionDefinition/stack_services,VersionDefinition/repository_version',
+    real: '/version_definitions/{id}?fields=VersionDefinition/*,operating_systems/repositories/Repositories/*,operating_systems/OperatingSystems/*,VersionDefinition/stack_services,VersionDefinition/repository_version',
   },
 
   'mpack.get_version_definitions': {
-    'real': '/version_definitions?fields=VersionDefinition/*,operating_systems/repositories/Repositories/*,operating_systems/OperatingSystems/*,VersionDefinition/stack_services,VersionDefinition/repository_version',
+    real: '/version_definitions?fields=VersionDefinition/*,operating_systems/repositories/Repositories/*,operating_systems/OperatingSystems/*,VersionDefinition/stack_services,VersionDefinition/repository_version',
+  },
+
+  'registry.all': {
+    real: '/registries?fields=mpacks/*,mpacks/versions/RegistryMpackVersionInfo/*,scenarios/*'
   },
 
   'registry.mpacks.versions': {
     real: '/registries?fields=mpacks/*,mpacks/versions/RegistryMpackVersionInfo/*',
-    mock: '/data/registry/mpacks_versions.json',
   },
 
   'registry.mpacks': {
     real: '/registries/{registryId}/mpacks',
-    mock: '/data/registry/mpacks.json',
   },
 
   'registry.mpack': {
     real: '/registries/{registryId}/mpacks/{name}',
-    mock: '/data/registry/mpack.json',
   },
 
   'registry.mpack.version': {
     real: '/registries/{registryId}/mpacks/{name}/versions/{version}',
-    mock: '/data/registry/mpack_version.json',
-  }
-
+  },
 
+  'registry.recommendation.usecases': {
+    real: '/registries/{registryId}/recommendations',
+    format: function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify({
+          recommend: "scenario-mpacks",
+          selected_scenarios: data.usecases
+        })
+      };
+    }
+  }
 };
 /**
  * Replace data-placeholders to its values

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/app/views/wizard/selectMpacks_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/wizard/selectMpacks_view.js b/ambari-web/app/views/wizard/selectMpacks_view.js
index deab12b..c4189ff 100644
--- a/ambari-web/app/views/wizard/selectMpacks_view.js
+++ b/ambari-web/app/views/wizard/selectMpacks_view.js
@@ -23,6 +23,65 @@ App.WizardSelectMpacksView = Em.View.extend({
 
   didInsertElement: function () {
     this.get('controller').loadStep();
+  },
+
+  toggleMode: function () {
+    const isAdvancedMode = this.get('controller.content.advancedMode');
+    const controller = this.get('controller');
+
+    if (isAdvancedMode) { //toggling to Basic Mode
+      this.showToggleToBasicBox(this.get('controller').toggleMode.bind(controller));
+    } else { //toggling to Advanced Mode
+      this.showToggleToAdvancedBox(this.get('controller').toggleMode.bind(controller));
+    }
+  },
+
+  showToggleToAdvancedBox: function (callback) {
+    App.ModalPopup.show({
+      primary: Em.I18n.t('installer.selectMpacks.basicMode'),
+      secondary: Em.I18n.t('installer.selectMpacks.advancedMode'),
+      header: Em.I18n.t('installer.selectMpacks.changeMode'),
+      body: Em.I18n.t('installer.selectMpacks.basicModeMessage'),
+      showCloseButton: false,
+      onPrimary: function () {
+        this._super();
+      },
+      onSecondary: function () {
+        this._super();
+        callback();
+      }
+    });
+  },
+
+  showToggleToBasicBox: function (callback) {
+    App.ModalPopup.show({
+      primary: Em.I18n.t('installer.selectMpacks.advancedMode'),
+      secondary: Em.I18n.t('installer.selectMpacks.basicMode'),
+      header: Em.I18n.t('installer.selectMpacks.changeMode'),
+      body: Em.I18n.t('installer.selectMpacks.advancedModeMessage'),
+      showCloseButton: false,
+      onPrimary: function () {
+        this._super();
+      },
+      onSecondary: function () {
+        this._super();
+        callback();
+      }
+    });
+  }
+})
+  
+/**
+ * View for each use case in the registry
+ */
+App.WizardUsecaseView = Em.View.extend({
+  templateName: require('templates/wizard/selectMpacks/usecase'),
+
+  /**
+   * Handle add/remove button clicked
+   */
+  toggle: function () {
+    this.get('controller').toggleUsecaseHandler(this.get('usecase.id'));
   }
 });
 
@@ -54,19 +113,45 @@ App.WizardMpackView = Em.View.extend({
   addService: function (event) {
     const serviceId = event.context;
     this.get('controller').addServiceHandler(serviceId);
+  },
+
+  addMpack: function (event) {
+    const version = this.get('mpack.versions').filterProperty('displayed')[0];
+    this.get('controller').addMpackHandler(version.get('id'));
   }
 });
 
 /**
+ * View for each service in the registry
+ */
+App.WizardServiceView = Em.View.extend({
+  templateName: require('templates/wizard/selectMpacks/service'),
+
+  /**
+   * Handle add button clicked
+   */
+  add: function () {
+    const service = this.get('service.versions').filterProperty('displayed')[0];
+    this.get('controller').addServiceHandler(service.get('id'));
+  },
+
+  /**
+   * Handle service version changed
+   * 
+   * @param {any} event 
+   */
+  changeVersion: function (event) {
+    const versionId = event.target.value;
+    this.get('controller').displayServiceVersion(versionId);
+  },
+});
+
+/**
  * View for each selected mpack
  */
 App.WizardSelectedMpackVersionView = Em.View.extend({
   templateName: require('templates/wizard/selectMpacks/selectedMpackVersion'),
 
-  mpack: function () {
-    return this.get('mpackVersion.mpack.name');
-  }.property(),
-
   /**
    * Handle remove service button clicked.
    *
@@ -75,5 +160,15 @@ App.WizardSelectedMpackVersionView = Em.View.extend({
   removeService: function (event) {
     const serviceId = event.context;
     this.get('controller').removeServiceHandler(serviceId);
+  },
+
+  /**
+   * Handle remove mpack button clicked.
+   * 
+   * @param {any} event 
+   */
+  removeMpack: function (event) {
+    const mpackId = event.context;
+    this.get('controller').removeMpackHandler(mpackId);
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b915f26/ambari-web/test/controllers/wizard/selectMpacks_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/selectMpacks_test.js b/ambari-web/test/controllers/wizard/selectMpacks_test.js
index 7102d91..13e28ce 100644
--- a/ambari-web/test/controllers/wizard/selectMpacks_test.js
+++ b/ambari-web/test/controllers/wizard/selectMpacks_test.js
@@ -332,12 +332,88 @@ var registry = {
             }
           ]
         }
+      ],
+      "scenarios": [
+        {
+          "href": "http://localhost:8080/api/v1/registries/1/scenarios/DataScience",
+          "RegistryScenarioInfo": {
+            "registry_id": 1,
+            "scenario_description": "Data Science and Machine Learning",
+            "scenario_mpacks": [
+              {
+                "name": "HDP"
+              },
+              {
+                "name": "HDS"
+              }
+            ],
+            "scenario_name": "DataScience"
+          }
+        },
+        {
+          "href": "http://localhost:8080/api/v1/registries/1/scenarios/EDW",
+          "RegistryScenarioInfo": {
+            "registry_id": 1,
+            "scenario_description": "EDW or SQL Analytics",
+            "scenario_mpacks": [
+              {
+                "name": "HDP"
+              },
+              {
+                "name": "EDW"
+              }
+            ],
+            "scenario_name": "EDW"
+          }
+        },
+        {
+          "href": "http://localhost:8080/api/v1/registries/1/scenarios/Hadoop",
+          "RegistryScenarioInfo": {
+            "registry_id": 1,
+            "scenario_description": "Hadoop Core",
+            "scenario_mpacks": [
+              {
+                "name": "HDP"
+              }
+            ],
+            "scenario_name": "Hadoop"
+          }
+        }
       ]
     }
   ]
 };
 
 describe('App.WizardSelectMpacksController', function () {
+  describe('#registryLoaded - before loading registry', function () {  
+    it('should not have a loaded registry', function () {
+      wizardController = App.InstallerController.create();
+      wizardController.set('steps', [
+        "step0",
+        "selectMpacks",
+        "step2",
+        "step3",
+        "step4"
+      ]);
+
+      wizardSelectMpacksController = App.WizardSelectMpacksController.create({
+        isSubmitDisabled: false,
+        selectedServices: null,
+        selectedMpackVersions: null,
+        content: {
+          selectedServices: null,
+          selectedServiceNames: null,
+          selectedMpacks: null
+        },
+        wizardController: wizardController
+      });
+
+      expect(wizardSelectMpacksController.registryLoaded()).to.be.false;
+    });
+  });  
+});
+
+describe('App.WizardSelectMpacksController', function () {
 
   before(function () {
     wizardController = App.InstallerController.create();
@@ -360,9 +436,16 @@ describe('App.WizardSelectMpacksController', function () {
       },
       wizardController: wizardController      
     });
+
     wizardSelectMpacksController.loadRegistrySucceeded(registry);
   });
 
+  describe('#registryLoaded - after loading registry', function () { 
+    it('should have a loaded registry', function () {
+      expect(wizardSelectMpacksController.registryLoaded()).to.be.true;
+    })
+  });
+
   describe('#loadStep', function () {
     it('adds previously selected services to selection', function () {
       wizardSelectMpacksController.set('content.selectedServices', [
@@ -372,16 +455,77 @@ describe('App.WizardSelectMpacksController', function () {
 
       wizardSelectMpacksController.loadStep();
       
-      var service = wizardSelectMpacksController.getServiceById("HDPCore3.0.0ZOOKEEPER");
+      var service = wizardSelectMpacksController.getServiceVersionById("HDPCore3.0.0ZOOKEEPER");
       expect(service.get('selected')).to.be.true;
       expect(service.get('mpackVersion.selected')).to.be.true;
 
-      var service = wizardSelectMpacksController.getServiceById("HDPCore3.0.0HDFS");
+      var service = wizardSelectMpacksController.getServiceVersionById("HDPCore3.0.0HDFS");
       expect(service.get('selected')).to.be.true;
       expect(service.get('mpackVersion.selected')).to.be.true;
     });
   });
 
+  describe('#getMpacksByName', function () {
+    it('should return an array of mpacks matching the given names', function () {
+      //this test assumes that mpackNames contains the names of all mpacks in the test registry data at the top of this file
+      var mpackNames = [
+        'EDW',
+        'HDPCore',
+        'HDS'
+      ]
+
+      var expected = wizardSelectMpacksController.get('content.mpacks');
+      var actual = wizardSelectMpacksController.getMpacksByName(mpackNames);
+      
+      expect(actual.length).to.equal(expected.length);
+      for (var i = 0, length = actual.length; i < length; i++) {
+        expect(actual[i].get('mpack.name')).to.equal(expected[i].get('name'));
+      }
+    });
+  });
+
+  describe('#getServiceVersionById', function () {
+    it('should return the correct service', function () {
+      var serviceVersions = [
+        Em.Object.create({ id: 0 }),
+        Em.Object.create({ id: 1 }),
+        Em.Object.create({ id: 2 }),
+      ];     
+      wizardSelectMpacksController.set('content.mpackServiceVersions', serviceVersions);
+      
+      var actual = wizardSelectMpacksController.getServiceVersionById(1);
+      expect(actual).to.equal(serviceVersions[1]);
+    });
+  });
+
+  describe('#getUsecaseById', function () {
+    it('should return the correct use case', function () {
+      var usecases = [
+        Em.Object.create({ id: 0 }),
+        Em.Object.create({ id: 1 }),
+        Em.Object.create({ id: 2 }),
+      ];
+      wizardSelectMpacksController.set('content.mpackUsecases', usecases);
+
+      var actual = wizardSelectMpacksController.getUsecaseById(1);
+      expect(actual).to.equal(usecases[1]);
+    });
+  });
+
+  describe('#getMpackVersionById', function () {
+    it('should return the correct mpack', function () {
+      var mpackVersions = [
+        Em.Object.create({ id: 0 }),
+        Em.Object.create({ id: 1 }),
+        Em.Object.create({ id: 2 }),
+      ];
+      wizardSelectMpacksController.set('content.mpackVersions', mpackVersions);
+
+      var actual = wizardSelectMpacksController.getMpackVersionById(1);
+      expect(actual).to.equal(mpackVersions[1]);
+    });
+  });
+
   describe('#displayMpackVersion', function () {
     var actual = {
       mpack: {
@@ -419,6 +563,43 @@ describe('App.WizardSelectMpacksController', function () {
     });
   });
 
+  describe('#displayServiceVersion', function () {
+    var actual = {
+      service: {
+        versions: [
+          Em.Object.create({ id: "1", displayed: true }),
+          Em.Object.create({ id: "2", displayed: false }),
+          Em.Object.create({ id: "3", displayed: false }),
+          Em.Object.create({ id: "4", displayed: false }),
+        ]
+      }
+    };
+
+    before(function () {
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById').returns(actual);
+    });
+
+    it('should set chosen service version to displayed and set others to not displayed', function () {
+      var expected = {
+        service: {
+          versions: [
+            Em.Object.create({ id: "1", displayed: false }),
+            Em.Object.create({ id: "2", displayed: false }),
+            Em.Object.create({ id: "3", displayed: true }),
+            Em.Object.create({ id: "4", displayed: false }),
+          ]
+        }
+      };
+
+      wizardSelectMpacksController.displayServiceVersion("3");
+      expect(actual).to.deep.equal(expected);
+    });
+
+    after(function () {
+      wizardSelectMpacksController.getServiceVersionById.restore();
+    });
+  });
+
   describe('#addServiceHandler', function () {
     var actual;
 
@@ -443,11 +624,11 @@ describe('App.WizardSelectMpacksController', function () {
         }
       });
 
-      sinon.stub(wizardSelectMpacksController, 'getServiceById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById').returns(actual);
     });
     
     after(function () {
-      wizardSelectMpacksController.getServiceById.restore();
+      wizardSelectMpacksController.getServiceVersionById.restore();
     });
 
     it('should set the service and its mpack to selected and set the step to unsaved', function () {
@@ -500,7 +681,7 @@ describe('App.WizardSelectMpacksController', function () {
       var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
       expect(savedState).to.deep.equal(final);
 
-      wizardSelectMpacksController.getServiceById.restore();
+      wizardSelectMpacksController.getServiceVersionById.restore();
     });
 
     it('should set only the service to not selected and set the step to unsaved', function () {
@@ -516,7 +697,7 @@ describe('App.WizardSelectMpacksController', function () {
         Em.Object.create({ selected: true })
       ]);
 
-      sinon.stub(wizardSelectMpacksController, 'getServiceById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById').returns(actual);
 
       wizardSelectMpacksController.removeServiceHandler("HDPCore3.0.0ZOOKEEPER");
       expect(actual.get('selected')).to.be.false;
@@ -536,7 +717,7 @@ describe('App.WizardSelectMpacksController', function () {
         Em.Object.create({ selected: false })
       ]);
 
-      sinon.stub(wizardSelectMpacksController, 'getServiceById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById').returns(actual);
 
       wizardSelectMpacksController.removeServiceHandler("HDPCore3.0.0ZOOKEEPER");
       expect(actual.get('selected')).to.be.false;
@@ -544,31 +725,233 @@ describe('App.WizardSelectMpacksController', function () {
     });
   });
 
+  describe('#addMpackHandler', function () {
+    var actual;
+
+    before(function () {
+      var initial = Em.Object.create({
+        "0": true,
+        "1": true,
+        "2": true,
+        "3": true,
+        "4": true
+      })
+      wizardSelectMpacksController.set('wizardController.content.stepsSavedState', initial);
+
+      var service0 = Em.Object.create({
+        id: 0,
+        selected: false
+      });
+
+      var service1 = Em.Object.create({
+        id: 1,
+        selected: false
+      });
+
+      actual = Em.Object.create({
+        selected: false,
+        services: [
+          service0,
+          service1
+        ]
+      });
+
+      actual.get('services')[0].set('mpackVersion', actual);
+      actual.get('services')[1].set('mpackVersion', actual);
+
+      sinon.stub(wizardSelectMpacksController, 'getMpackVersionById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById')
+        .withArgs(0).returns(service0)
+        .withArgs(1).returns(service1);
+    });
+
+    after(function () {
+      wizardSelectMpacksController.getMpackVersionById.restore();
+      wizardSelectMpacksController.getServiceVersionById.restore();
+    });
+
+    it('should set the mpack and all of its services to selected and set the step to unsaved', function () {
+      var expected = Em.Object.create({
+        selected: true,
+        services: [
+          Em.Object.create({
+            id: 0,
+            selected: true
+          }),
+          Em.Object.create({
+            id: 1,
+            selected: true
+          })
+        ]
+      });
+      expected.get('services')[0].set('mpackVersion', expected);
+      expected.get('services')[1].set('mpackVersion', expected);
+
+      wizardSelectMpacksController.addMpackHandler("HDPCore3.0.0");
+      expect(actual).to.deep.equal(expected);
+
+      var final = Em.Object.create({
+        "0": true,
+        "1": false,
+        "2": true,
+        "3": true,
+        "4": true
+      });
+      var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
+      expect(savedState).to.deep.equal(final);
+    });
+  });
+
+  describe('#removeMpackHandler', function () {
+    before(function () {
+      var initial = Em.Object.create({
+        "0": true,
+        "1": true,
+        "2": true,
+        "3": true,
+        "4": true
+      })
+      wizardSelectMpacksController.set('wizardController.content.stepsSavedState', initial);
+
+      var service0 = Em.Object.create({
+        id: 0,
+        selected: true
+      });
+
+      var service1 = Em.Object.create({
+        id: 1,
+        selected: true
+      });
+
+      actual = Em.Object.create({
+        selected: true,
+        services: [
+          service0,
+          service1
+        ]
+      });
+
+      actual.get('services')[0].set('mpackVersion', actual);
+      actual.get('services')[1].set('mpackVersion', actual);
+
+      sinon.stub(wizardSelectMpacksController, 'getMpackVersionById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'getServiceVersionById')
+        .withArgs(0).returns(service0)
+        .withArgs(1).returns(service1);
+    });
+
+    after(function () {
+      wizardSelectMpacksController.getMpackVersionById.restore();
+      wizardSelectMpacksController.getServiceVersionById.restore();
+    });
+
+    it('should set the mpack and all its services to not selected and set the step to unsaved', function () {
+      var expected = Em.Object.create({
+        selected: false,
+        services: [
+          Em.Object.create({
+            id: 0,
+            selected: false
+          }),
+          Em.Object.create({
+            id: 1,
+            selected: false
+          })
+        ]
+      });
+      expected.get('services')[0].set('mpackVersion', expected);
+      expected.get('services')[1].set('mpackVersion', expected);
+
+      wizardSelectMpacksController.removeMpackHandler("HDPCore3.0.0");
+      expect(actual).to.deep.equal(expected);
+      
+      var final = Em.Object.create({
+        "0": true,
+        "1": false,
+        "2": true,
+        "3": true,
+        "4": true
+      });
+      var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
+      expect(savedState).to.deep.equal(final);
+    });
+  });
+
   describe('#clearSelection', function () {
-    it('should set all services and mpacks to be unselected', function () {
-      var servicesActual = [
+    var initial, servicesActual, versionsActual, usecasesActual, expected, final;
+
+    beforeEach(function () {
+      initial = Em.Object.create({
+        "0": true,
+        "1": true,
+        "2": true,
+        "3": true,
+        "4": true
+      });
+      wizardSelectMpacksController.set('wizardController.content.stepsSavedState', initial);
+
+      final = Em.Object.create({
+        "0": true,
+        "1": false,
+        "2": true,
+        "3": true,
+        "4": true
+      });
+
+      servicesActual = [
         Em.Object.create({ selected: true }),
         Em.Object.create({ selected: true }),
         Em.Object.create({ selected: true })
       ];
-      wizardSelectMpacksController.set('content.mpackServices', servicesActual);
+      wizardSelectMpacksController.set('content.mpackServiceVersions', servicesActual);
 
-      var versionsActual = [
+      versionsActual = [
         Em.Object.create({ selected: true }),
         Em.Object.create({ selected: true }),
         Em.Object.create({ selected: true })
       ];
       wizardSelectMpacksController.set('content.mpackVersions', versionsActual);
 
-      var expected = [
+      usecasesActual = [
+        Em.Object.create({ selected: true }),
+        Em.Object.create({ selected: true }),
+        Em.Object.create({ selected: true })
+      ];
+      wizardSelectMpacksController.set('content.mpackUsecases', usecasesActual);
+
+      expected = [
         Em.Object.create({ selected: false }),
         Em.Object.create({ selected: false }),
         Em.Object.create({ selected: false })
       ];
+    });
+    
+    it('should set all services and mpacks to be unselected and set the step to unsaved', function () {
+      wizardSelectMpacksController.set('content.advancedMode', false);
+      wizardSelectMpacksController.clearSelection();
+      expect(servicesActual).to.deep.equal(expected);
+      expect(versionsActual).to.deep.equal(expected);
+       
+      //should not be changed
+      expect(usecasesActual).to.deep.equal([
+        Em.Object.create({ selected: true }),
+        Em.Object.create({ selected: true }),
+        Em.Object.create({ selected: true })
+      ]);
+
+      var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
+      expect(savedState).to.deep.equal(final);
+    });
 
+    it('should set all usecases to be unselected in advanced mode', function () {
+      wizardSelectMpacksController.set('content.advancedMode', true);
       wizardSelectMpacksController.clearSelection();
       expect(servicesActual).to.deep.equal(expected);
       expect(versionsActual).to.deep.equal(expected);
+      expect(usecasesActual).to.deep.equal(expected);
+
+      var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
+      expect(savedState).to.deep.equal(final);
     });
   });
 
@@ -662,6 +1045,121 @@ describe('App.WizardSelectMpacksController', function () {
       expect(wizardSelectMpacksController.get('content.selectedServices')).to.deep.equal(expectedSelectedServices);
       expect(wizardSelectMpacksController.get('content.selectedServiceNames')).to.deep.equal(expectedSelectedServiceNames);
       expect(wizardSelectMpacksController.get('content.selectedMpacks')).to.deep.equal(expectedSelectedMpacks);
-    })
-  })
+    });
+  });
+
+  describe('#toggleUsecaseHandler', function () {
+    beforeEach(function () {
+      var initial = Em.Object.create({
+        "0": true,
+        "1": true,
+        "2": true,
+        "3": true,
+        "4": true
+      })
+      wizardSelectMpacksController.set('wizardController.content.stepsSavedState', initial);
+
+      sinon.stub(wizardSelectMpacksController, 'getUsecaseRecommendation').returns({
+        done: sinon.stub().returns({ fail: sinon.stub() })
+      });
+    });
+
+    afterEach(function () {
+      var final = Em.Object.create({
+        "0": true,
+        "1": false,
+        "2": true,
+        "3": true,
+        "4": true
+      });
+      var savedState = wizardSelectMpacksController.get('wizardController.content.stepsSavedState');
+      expect(savedState).to.deep.equal(final);
+
+      wizardSelectMpacksController.getUsecaseById.restore();
+      wizardSelectMpacksController.getUsecaseRecommendation.restore();
+    });
+
+    it('should select usecase when it is not already selected', function () {
+      var actual = Em.Object.create({
+        selected: false
+      });
+
+      wizardSelectMpacksController.set('content.mpackUsecases', [
+        Em.Object.create({
+          selected: false
+        }),
+        actual
+      ]);
+
+      sinon.stub(wizardSelectMpacksController, 'getUsecaseById').returns(actual);
+
+      wizardSelectMpacksController.toggleUsecaseHandler("DataScience");
+      expect(actual.get('selected')).to.be.true;
+      expect(wizardSelectMpacksController.getUsecaseRecommendation).to.have.been.called;
+    });
+
+    it('should deselect use case when it is already selected', function () {
+      var actual = Em.Object.create({
+        selected: true
+      });
+      
+      wizardSelectMpacksController.set('content.mpackUsecases', [
+        Em.Object.create({
+          selected: true
+        }),
+        actual
+      ]);
+      
+      sinon.stub(wizardSelectMpacksController, 'getUsecaseById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'clearSelection');
+
+      wizardSelectMpacksController.toggleUsecaseHandler("DataScience");
+      expect(actual.get('selected')).to.be.false;
+      expect(wizardSelectMpacksController.getUsecaseRecommendation).to.have.been.called;
+      
+      wizardSelectMpacksController.clearSelection.restore();
+    });
+
+    it('should not call getUsecaseRecommendation when no use cases are selected', function () {
+      var actual = Em.Object.create({
+        selected: true
+      });
+
+      wizardSelectMpacksController.set('content.mpackUsecases', [
+        Em.Object.create({
+          selected: false
+        }),
+        actual
+      ]);
+
+      sinon.stub(wizardSelectMpacksController, 'getUsecaseById').returns(actual);
+      sinon.stub(wizardSelectMpacksController, 'clearSelection');
+
+      wizardSelectMpacksController.toggleUsecaseHandler("DataScience");
+      expect(actual.get('selected')).to.be.false;
+      expect(wizardSelectMpacksController.getUsecaseRecommendation).to.not.have.been.called;
+
+      wizardSelectMpacksController.clearSelection.restore();
+    });
+  });
+
+  describe('#toggleMode', function () {
+    it('should set mode to advanced', function () {
+      wizardSelectMpacksController.set('content.advancedMode', false);
+      wizardSelectMpacksController.toggleMode();
+      expect(wizardSelectMpacksController.get('content.advancedMode')).to.be.true;
+    });
+
+    it('should set mode to basic', function () {
+      wizardSelectMpacksController.set('content.advancedMode', true);
+      sinon.stub(wizardSelectMpacksController, 'clearSelection');
+
+      wizardSelectMpacksController.toggleMode();
+
+      expect(wizardSelectMpacksController.get('content.advancedMode')).to.be.false;
+      expect(wizardSelectMpacksController.clearSelection).to.have.been.called
+
+      wizardSelectMpacksController.clearSelection.restore();
+    });
+  });
 });