AMBARI-22311 - Initial implementation of mpack install wizard (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/15347746 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/15347746 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/15347746 Branch: refs/heads/branch-feature-AMBARI-14714-ui Commit: 153477463207d78182dca46a9048f1ac97e611fd Parents: 1578226b Author: Jonathan Hurley <[email protected]> Authored: Fri Oct 27 16:47:10 2017 -0400 Committer: Jonathan Hurley <[email protected]> Committed: Fri Oct 27 16:47:10 2017 -0400 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 1 + ambari-web/app/controllers.js | 1 + ambari-web/app/controllers/installer.js | 235 +++++++++++-------- ambari-web/app/controllers/wizard.js | 30 ++- .../wizard/configureDownload_controller.js | 102 +++----- .../wizard/downloadProducts_controller.js | 125 +++++++--- .../wizard/selectMpacks_controller.js | 203 ++++++++++++++++ .../app/controllers/wizard/step7_controller.js | 9 +- .../app/controllers/wizard/step8_controller.js | 99 ++++---- ambari-web/app/mappers.js | 3 +- ambari-web/app/mappers/mpack_service_mapper.js | 114 +++++++++ ambari-web/app/mappers/stack_mapper.js | 11 +- ambari-web/app/messages.js | 6 + .../app/mixins/wizard/wizard_menu_view.js | 10 +- ambari-web/app/models/stack.js | 2 - ambari-web/app/router.js | 6 +- ambari-web/app/routes/installer.js | 200 +++++++++------- ambari-web/app/templates/installer.hbs | 17 +- .../app/templates/wizard/configureDownload.hbs | 63 +++-- .../app/templates/wizard/downloadProducts.hbs | 4 +- .../app/templates/wizard/selectMpacks.hbs | 70 ++++++ .../app/templates/wizard/selectMpacks/mpack.hbs | 31 +++ .../selectMpacks/selectedMpackVersion.hbs | 32 +++ ambari-web/app/utils/ajax/ajax.js | 66 ++++++ ambari-web/app/views.js | 3 + .../app/views/wizard/configureDownload_view.js | 8 +- .../app/views/wizard/selectMpacks/mpack_view.js | 31 +++ .../selectMpacks/selectedMpackVersion_view.js | 27 +++ .../app/views/wizard/selectMpacks_view.js | 28 +++ ambari-web/test/controllers/installer_test.js | 71 ------ .../controllers/wizard/selectMpacks_test.js | 42 ++++ .../test/controllers/wizard/step8_test.js | 90 +++++-- .../test/mixins/routers/redirections_test.js | 8 +- ambari-web/test/views/installer_test.js | 16 +- 34 files changed, 1252 insertions(+), 512 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index 7c636d4..b60e17a 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -135,6 +135,7 @@ var files = [ 'test/controllers/login_controller_test', 'test/controllers/experimental_test', 'test/controllers/wizard_test', + 'test/controllers/wizard/selectMpacks_test', 'test/controllers/wizard/step0_test', 'test/controllers/wizard/step1_test', 'test/controllers/wizard/step2_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js index 82b0f66..5af0937 100644 --- a/ambari-web/app/controllers.js +++ b/ambari-web/app/controllers.js @@ -160,6 +160,7 @@ require('controllers/wizard/step7/pre_install_checks_controller'); require('controllers/wizard/step8_controller'); require('controllers/wizard/step9_controller'); require('controllers/wizard/step10_controller'); +require('controllers/wizard/selectMpacks_controller'); require('controllers/global/cluster_controller'); require('controllers/global/update_controller'); require('controllers/global/configuration_controller'); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers/installer.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js index d4f656b..5dd0941 100644 --- a/ambari-web/app/controllers/installer.js +++ b/ambari-web/app/controllers/installer.js @@ -42,9 +42,10 @@ App.InstallerController = App.WizardController.extend(App.Persist, { "step2", "step3", "configureDownload", + "selectMpacks", "downloadProducts", - "step1", - "step4", + //"step1", + //"step4", "step5", "step6", "step7", @@ -78,7 +79,10 @@ App.InstallerController = App.WizardController.extend(App.Persist, { * (uses for host groups validation and to load recommended configs) */ recommendationsHostGroups: null, - controllerName: 'installerController' + controllerName: 'installerController', + mpacks: [], + mpackVersions: [], + mpackServices: [] }), /** @@ -109,7 +113,11 @@ App.InstallerController = App.WizardController.extend(App.Persist, { 'recommendationsConfigs', 'componentsFromConfigs', 'operatingSystems', - 'repositories' + 'repositories', + 'selectedMpacks', + 'selectedServices', + 'selectedStack', + 'downloadConfig' ], init: function () { @@ -177,6 +185,74 @@ App.InstallerController = App.WizardController.extend(App.Persist, { }, /** + * Load data for stacks from selected mpacks. This just tells the server to populate the version_definitions endpoint for the mpack that was registered. + * + * @param {string} stackName + * @param {string} stackVersion + * @param {string} serviceName + */ + createMpackStackVersion: function (stackName, stackVersion) { + return App.ajax.send({ + name: 'mpack.create_version_definition', + sender: this, + data: { + name: stackName, + version: stackVersion + } + }) + }, + + /** + * Loads stack version data (including supported OSes and repos) from the version_definitions endpoint + */ + getMpackStackVersions: function () { + return App.ajax.send({ + name: 'mpack.get_version_definitions', + sender: this + }) + }, + + loadMpackStackInfoSuccess: function (versionDefinition) { + App.stackMapper.map(versionDefinition); + }, + + //TODO: report error in UI + loadMpackStackInfoError: function(request, status, error) { + console.log(`Failed to load stack info. ${status} - ${error}`); + }, + + /** + * Load data for services selected from mpacks. Will be used at <code>Download Mpacks</code> step submit action. + * + * @param {string} stackName + * @param {string} stackVersion + * @param {string} serviceName + */ + loadMpackServiceInfo: function (stackName, stackVersion, serviceName) { + return App.ajax.send({ + name: 'wizard.mpack_service_components', + sender: this, + data: { + stackName: stackName || "HDP", //TODO: mpacks - Remove default when this value is provided API + stackVersion: stackVersion, + serviceName: serviceName + }, + success: 'loadMpackServiceInfoSuccess', + error: 'loadMpackServiceInfoError' + }) + }, + + loadMpackServiceInfoSuccess: function (serviceInfo) { + serviceInfo.StackServices.is_selected = true; + App.MpackServiceMapper.map(serviceInfo); + }, + + //TODO: report error in UI + loadMpackServiceInfoError: function(request, status, error) { + console.log(`Failed to load mpack service info. ${status} - ${error}`); + }, + + /** * total set of hosts registered to cluster, analog of App.Host model, * used in Installer wizard until hosts are installed */ @@ -972,87 +1048,55 @@ App.InstallerController = App.WizardController.extend(App.Persist, { return dfd.promise(); } }, - { - type: 'async', - callback: function (stacksLoaded) { - var dfd = $.Deferred(); - - if (!stacksLoaded) { - $.when.apply(this, this.loadStacksVersions()).done(function () { - dfd.resolve(true); - }); - } else { - dfd.resolve(stacksLoaded); - } - - return dfd.promise(); - } - } - ], - 'downloadProducts': [ - { - type: 'async', - callback: function () { - var dfd = $.Deferred(); - - this.loadStacks().done(function(stacksLoaded) { - App.router.get('clusterController').loadAmbariProperties().always(function() { - dfd.resolve(stacksLoaded); - }); - }); - - return dfd.promise(); - } - }, - { - type: 'async', - callback: function (stacksLoaded) { - var dfd = $.Deferred(); - - if (!stacksLoaded) { - $.when.apply(this, this.loadStacksVersions()).done(function () { - dfd.resolve(true); - }); - } else { - dfd.resolve(stacksLoaded); - } - - return dfd.promise(); - } - } - ], - 'step1': [ - { - type: 'async', - callback: function () { - var dfd = $.Deferred(); - - this.loadStacks().done(function(stacksLoaded) { - App.router.get('clusterController').loadAmbariProperties().always(function() { - dfd.resolve(stacksLoaded); - }); - }); - - return dfd.promise(); - } - }, - { - type: 'async', - callback: function (stacksLoaded) { - var dfd = $.Deferred(); - - if (!stacksLoaded) { - $.when.apply(this, this.loadStacksVersions()).done(function () { - dfd.resolve(true); - }); - } else { - dfd.resolve(stacksLoaded); - } - - return dfd.promise(); - } - } + // { + // type: 'async', + // callback: function (stacksLoaded) { + // var dfd = $.Deferred(); + // + // if (!stacksLoaded) { + // $.when.apply(this, this.loadStacksVersions()).done(function () { + // dfd.resolve(true); + // }); + // } else { + // dfd.resolve(stacksLoaded); + // } + // + // return dfd.promise(); + // } + // } ], + // 'step1': [ + // { + // type: 'async', + // callback: function () { + // var dfd = $.Deferred(); + // + // this.loadStacks().done(function(stacksLoaded) { + // App.router.get('clusterController').loadAmbariProperties().always(function() { + // dfd.resolve(stacksLoaded); + // }); + // }); + // + // return dfd.promise(); + // } + // }, + // { + // type: 'async', + // callback: function (stacksLoaded) { + // var dfd = $.Deferred(); + // + // if (!stacksLoaded) { + // $.when.apply(this, this.loadStacksVersions()).done(function () { + // dfd.resolve(true); + // }); + // } else { + // dfd.resolve(stacksLoaded); + // } + // + // return dfd.promise(); + // } + // } + // ], 'step3': [ { type: 'sync', @@ -1061,20 +1105,19 @@ App.InstallerController = App.WizardController.extend(App.Persist, { } } ], - - 'step4': [ - { - type: 'async', - callback: function () { - return this.loadServices(); - } - } - ], + // 'step4': [ + // { + // type: 'async', + // callback: function () { + // return this.loadServices(); + // } + // } + // ], 'step5': [ { type: 'sync', callback: function () { - this.setSkipSlavesStep(App.StackService.find().filterProperty('isSelected'), 6); + this.setSkipSlavesStep(App.StackService.find().filterProperty('isSelected'), 6); //TODO: something needs to be changed here this.loadMasterComponentHosts(); this.loadConfirmedHosts(); this.loadComponentsFromConfigs(); @@ -1180,6 +1223,10 @@ App.InstallerController = App.WizardController.extend(App.Persist, { this.gotoStep('downloadProducts'); }, + gotoSelectMpacks: function () { + this.gotoStep('selectMpacks'); + }, + isStep0: function () { return this.get('currentStep') == this.getStepIndex('step0'); }.property('currentStep'), http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers/wizard.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard.js b/ambari-web/app/controllers/wizard.js index 9db923e..540cc63 100644 --- a/ambari-web/app/controllers/wizard.js +++ b/ambari-web/app/controllers/wizard.js @@ -323,7 +323,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM App.ModalPopup.show({ header: Em.I18n.t('installer.navigation.warning.header'), onPrimary: function () { - App.router.send('gotoStep' + step); + App.router.send('goto' + stepName.capitalize()); this.hide(); }, body: "If you proceed to go back to Step " + step + ", you will lose any changes you have made beyond this step" @@ -379,14 +379,6 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM this.gotoStep(10); }, - gotoConfigureDownload: function () { - this.gotoStep("configureDownload"); - }, - - gotoDownloadProducts: function () { - this.gotoStep("downloadProducts"); - }, - /** * Initialize host status info for step9 */ @@ -629,6 +621,12 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM this.set('content.' + name, result); }, + + /** + * Save value from content to database. Converts Ember objects to plain objects first. + * + * @param {type} name + */ save: function (name) { var convertedValue = this.toJSInstance(this.get('content.' + name)); this.setDBProperty(name, convertedValue); @@ -1572,6 +1570,20 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM this.setDBProperty('kerberosDescriptorConfigs', kerberosDescriptorConfigs); this.set('kerberosDescriptorConfigs', kerberosDescriptorConfigs); }, + + getStack: function (name, version) { + const stacks = App.Stack.find(); + + for (let i = 0, length = stacks.get('length'); i < length; i++) { + const stack = stacks.objectAt(i); + if (stack.get('stackName') === name && stack.get('stackVersion') === version) { + return stack; + } + } + + return null; + }, + /** * reset stored wizard data and reload App * @param {App.WizardController} controller - wizard controller http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers/wizard/configureDownload_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/configureDownload_controller.js b/ambari-web/app/controllers/wizard/configureDownload_controller.js index a80cf25..f3a8b1b 100644 --- a/ambari-web/app/controllers/wizard/configureDownload_controller.js +++ b/ambari-web/app/controllers/wizard/configureDownload_controller.js @@ -17,38 +17,11 @@ */ var App = require('app'); -var arrayUtils = require('utils/array_utils'); - -/** - * @typedef {Em.Object} StackType - * @property {string} stackName - * @property {App.Stack[]} stacks - * @property {boolean} isSelected - */ - -/** - * @type {Em.Object} - */ -var StackType = Em.Object.extend({ - stackName: '', - stacks: [], - isSelected: Em.computed.someBy('stacks', 'isSelected', true) -}); App.WizardConfigureDownloadController = Em.Controller.extend({ name: 'wizardConfigureDownloadController', - /** - * @type {App.Stack} - */ - selectedStack: Em.computed.findBy('content.stacks', 'isSelected', true), - - /** - * @type {App.ServiceSimple[]} - */ - servicesForSelectedStack: Em.computed.filterBy('selectedStack.stackServices', 'isHidden', false), - optionsToSelect: { 'usePublicRepo': { index: 0, @@ -75,55 +48,50 @@ App.WizardConfigureDownloadController = Em.Controller.extend({ } }, + loadStep: function () { + if (!this.get('content.downloadConfig')) { + let downloadConfig = this.get('wizardController').getDBProperty('downloadConfig'); + + if (!downloadConfig) { + downloadConfig = { + useRedhatSatellite: false, + usePublicRepo: true + }; + } + + this.set('content.downloadConfig', downloadConfig); + } + }, + /** * Restore base urls for selected stack when user select to use public repository */ usePublicRepo: function () { - var selectedStack = this.get('selectedStack'); - if (selectedStack) { - selectedStack.setProperties({ - useRedhatSatellite: false, - usePublicRepo: true, - useLocalRepo: false - }); - selectedStack.restoreReposBaseUrls(); - } + this.set('content.downloadConfig', { + useRedhatSatellite: false, + usePublicRepo: true + }); }, - /** - * Clean base urls for selected stack when user select to use local repository - */ useLocalRepo: function () { - var selectedStack = this.get('selectedStack'); - if (selectedStack) { - selectedStack.setProperties({ - usePublicRepo: false, - useLocalRepo: true - }); - selectedStack.cleanReposBaseUrls(); - } + this.set('content.downloadConfig', { + useRedhatSatellite: false, + usePublicRepo: false + }); }, - /** - * List of stacks grouped by <code>stackNameVersion</code> - * - * @type {StackType[]} - */ - availableStackTypes: function () { - var stacks = this.get('content.stacks'); - return stacks ? stacks.mapProperty('stackNameVersion').uniq().sort().reverse().map(function (stackName) { - return StackType.create({ - stackName: stackName, - stacks: stacks.filterProperty('stackNameVersion', stackName).sort(arrayUtils.sortByIdAsVersion).reverse() - }) - }) : []; - }.property('[email protected]'), - - /** - * @type {StackType} - */ - selectedStackType: Em.computed.findBy('availableStackTypes', 'isSelected', true), + /** + * Onclick handler for <code>Next</code> button. + * Disable 'Next' button while it is already under process. (using Router's property 'nextBtnClickInProgress') + * @method submit + */ + submit: function () { + if (App.get('router.nextBtnClickInProgress')) { + return; + } - isLoadingComplete: Em.computed.equal('wizardController.loadStacksRequestsCounter', 0) + this.get('wizardController').setDBProperty('downloadConfig', this.get('content.downloadConfig')); + App.router.send('next'); + } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/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 7e95acf..165debb 100644 --- a/ambari-web/app/controllers/wizard/downloadProducts_controller.js +++ b/ambari-web/app/controllers/wizard/downloadProducts_controller.js @@ -16,49 +16,26 @@ */ var App = require('app'); -var arrayUtils = require('utils/array_utils'); App.WizardDownloadProductsController = Em.Controller.extend({ name: 'wizardDownloadProductsController', - selectedMpacks: - [ - { - "mpackName" : "HDP", - "displayName": "Hortonworks Data Platform Core", - "mpackVersion" : "3.0.0", - "registryId" : "1" - }, - { - "mpackName" : "EDW", - "displayName": "Data Warehousing", - "mpackVersion": "1.0.0", - "registryId": "1" - }, - { - "mpackName" : "HDS", - "displayName": "Data Science and Machine Learning", - "mpackVersion" : "3.0.0.0", - "registryId" : "1" - } - ], - mpacks: [], addMpacks: function () { - var self = this; - this.get('selectedMpacks').forEach( function (mpack) { - self.get('mpacks').pushObject(Em.Object.create({ - name: mpack.mpackName, - displayName: mpack.displayName, - version: mpack.mpackVersion, - registryId:mpack.registryId, + const selectedMpacks = this.get('content.selectedMpacks') || this.get('wizardController').getDBProperty('selectedMpacks'); + + 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 + url: mpack.url, inProgress: true, failed: false, success: false })); - }); + }, this); }, registerMpacks: function () { @@ -72,12 +49,11 @@ App.WizardDownloadProductsController = Em.Controller.extend({ downloadMpack: function (mpack) { console.log("downloading mpacks"); App.ajax.send({ - name:'mpack.download', + name: 'mpack.download_by_url', sender: this, data: { name: mpack.name, - version: mpack.version, - registry: mpack.registryId + url: mpack.url }, success: 'downloadMpackSuccess', error: 'downloadMpackError', @@ -105,6 +81,83 @@ App.WizardDownloadProductsController = Em.Controller.extend({ mpack.set('inProgress', true); mpack.set('failed', false); this.downloadMpack(mpack); - } + }, + + getRegisteredMpacks: function () { + return App.ajax.send({ + name: 'mpack.get_registered_mpacks', + sender: this + }); + }, -}); \ No newline at end of file + isSubmitDisabled: function () { + const mpacks = this.get('mpacks'); + return mpacks.filterProperty('success', false).length > 0 || App.get('router.btnClickInProgress'); + }.property('[email protected]', 'App.router.btnClickInProgress'), + + /** + * Onclick handler for <code>Next</code> button. + * Disable 'Next' button while it is already under process. (using Router's property 'nextBtnClickInProgress') + * @method submit + */ + submit: function () { + const self = this; + + if (App.get('router.nextBtnClickInProgress')) { + return; + } + + 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 + ) + ); + + //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 + self.get('wizardController').getMpackStackVersions().then(data => { + data.items.forEach(versionDefinition => App.stackMapper.map(versionDefinition)) + + //get info about services from specific stack versions and save to StackService model + const selectedServices = self.get('content.selectedServices') || self.get('wizardController').getDBProperty('selectedServices'); + const servicePromises = selectedServices.map(service => self.get('wizardController').loadMpackServiceInfo(service.stackName, service.stackVersion, service.name)); + + $.when(...servicePromises).then(() => { + const serviceInfo = App.StackService.find(); + self.set('content.services', serviceInfo); + + const clients = []; + serviceInfo.forEach(service => { + const client = service.get('serviceComponents').filterProperty('isClient', true); + client.forEach(clientComponent => { + clients.pushObject({ + component_name: clientComponent.get('componentName'), + display_name: clientComponent.get('displayName'), + isInstalled: false + }); + }); + }); + self.set('content.clients', clients); + self.get('wizardController').setDBProperty('clientInfo', clients); + + // - for now, pull the stack from the single mpack that we can install + // - when we can support multiple mpacks, make this an array of selectedStacks (or just use the selectedServices array?) and add the repo data to it + const selectedService = selectedServices[0]; + const selectedStack = self.get('wizardController').getStack(selectedService.stackName, selectedService.stackVersion); + self.set('content.selectedStack', selectedStack); + self.get('wizardController').setDBProperty('selectedStack', selectedStack); + + App.router.send('next'); + }); + }); + }); + }); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/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 new file mode 100644 index 0000000..9ab5a12 --- /dev/null +++ b/ambari-web/app/controllers/wizard/selectMpacks_controller.js @@ -0,0 +1,203 @@ +/** + * 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. + */ + +var App = require('app'); + +App.WizardSelectMpacksController = Em.Controller.extend({ + + name: 'wizardSelectMpacksController', + + //mpacks: Em.computed.alias('content.mpacks'), + + getMpacks: function () { + App.ajax.send({ + name: 'registry.mpacks.versions', + showLoadingPopup: true, + sender: this, + success: 'getMpacksSucceeded', + error: 'getMpacksFailed' + }); + }, + + getMpacksSucceeded: function (data) { + const mpacks = data.items.reduce( + (mpacks, registry) => mpacks.concat( + registry.mpacks.map(mpack => { + return Em.Object.create({ + name: mpack.RegistryMpackInfo.mpack_name, + description: mpack.RegistryMpackInfo.mpack_description, + logoUrl: mpack.RegistryMpackInfo.mpack_logo_url, + versions: mpack.versions ? mpack.versions.map(version => { + return Em.Object.create({ + selected: false, + id: mpack.RegistryMpackInfo.mpack_name + version.RegistryMpackVersionInfo.mpack_version, + 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 + services: version.RegistryMpackVersionInfo.services ? version.RegistryMpackVersionInfo.services.map(service => { + return Em.Object.create({ + selected: false, + id: mpack.RegistryMpackInfo.mpack_name + version.RegistryMpackVersionInfo.mpack_version + service.name, + name: service.name, + version: service.version + }) + }) : [] + }) + }) : [] + }) + }) + ), + []); + + const mpackVersions = mpacks.reduce( + (versions, mpack) => versions.concat( + mpack.versions.map(version => { + version.mpack = mpack; + return version; + }) + ), + []); + + const mpackServices = mpackVersions.reduce( + (services, mpackVersion) => services.concat( + mpackVersion.services.map(service => { + service.mpackVersion = mpackVersion; + return service; + }) + ), + []); + + this.set('content.mpacks', mpacks); + this.set('content.mpackVersions', mpackVersions); + this.set('content.mpackServices', mpackServices); + }, + + getMpacksFailed: function () { + this.set('content.mpacks', []); + }, + + loadStep: function () { + const mpacks = this.get('content.mpacks'); + const mpackVersions = this.get('content.mpackVersions'); + const mpackServices = this.get('content.mpackServices'); + + if (!mpacks || mpacks.length === 0 || !mpackVersions || mpackVersions.length === 0 || !mpackServices || mpackServices.length === 0) { + //this.showLoadingSpinner(); + this.getMpacks(); + } + }, + + isSubmitDisabled: function () { + const mpackServices = this.get('content.mpackServices'); + return mpackServices.filterProperty('selected', true).length === 0 || App.get('router.btnClickInProgress'); + }.property('[email protected]', 'App.router.btnClickInProgress'), + + loadSelectionFailed: function () { + App.showAlertPopup( + Em.I18n.t('common.error'), //header + Em.I18n.t('installer.selectMpacks.loadSelectionFailed') //body + ); + }, + + /** + * Adds service to selection. + * + * @param {string} serviceName + */ + selectService: function (event) { + const serviceId = event.context; + const mpackServices = this.get('content.mpackServices'); + const byServiceId = service => service.id === serviceId; + + const service = mpackServices.find(byServiceId); + service.set('selected', true); + service.set('mpackVersion.selected', true); + }, + + removeService: function (event) { + const serviceId = event.context; + const mpackServices = this.get('content.mpackServices'); + const byServiceId = service => service.id === serviceId; + + const service = mpackServices.find(byServiceId); + service.set('selected', false); + + service.set('mpackVersion.selected', service.get('mpackVersion.services').some(s => s.get('selected') === true)); + }, + + selectedServices: function () { + const mpackServices = this.get('content.mpackServices'); + return mpackServices ? mpackServices.filter(s => s.get('selected') === true) : []; + }.property('[email protected]'), + + selectedMpackVersions: function () { + const versions = this.get('content.mpackVersions'); + return versions ? versions.filter(v => v.get('selected') === true) : []; + }.property('[email protected]', 'selectedServices'), + + hasSelectedMpackVersions: function () { + const versions = this.get('content.mpackVersions'); + return versions ? versions.some(v => v.get('selected') === true) : false; + }.property('[email protected]', 'selectedServices'), + + /** + * Onclick handler for <code>Next</code> button. + * Disable 'Next' button while it is already under process. (using Router's property 'nextBtnClickInProgress') + * @method submit + */ + submit: function () { + const self = this; + + if(App.get('router.nextBtnClickInProgress')) { + return; + } + + if (!this.get('isSubmitDisabled')) { + const selectedServices = this.get('selectedServices').map(service => + ({ + name: service.name, + mpackName: service.mpackVersion.name, + mpackVersion: service.mpackVersion.version, + stackName: service.mpackVersion.stackName, + stackVersion: service.mpackVersion.stackVersion + }) + ); + self.set('content.selectedServices', selectedServices); + self.get('wizardController').setDBProperty('selectedServices', selectedServices); + + const selectedServiceNames = selectedServices.map(service => service.name); + self.set('content.selectedServiceNames', selectedServiceNames); + self.get('wizardController').setDBProperty('selectedServiceNames', selectedServiceNames); + + const selectedMpacks = self.get('selectedMpackVersions').map(mpackVersion => + ({ + name: mpackVersion.mpack.name, + displayName: mpackVersion.mpack.displayName, + url: mpackVersion.mpackUrl, + version: mpackVersion.version + }) + ); + self.set('content.selectedMpacks', selectedMpacks); + self.get('wizardController').setDBProperty('selectedMpacks', selectedMpacks); + + App.router.send('next'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers/wizard/step7_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js index 3b71305..3def063 100644 --- a/ambari-web/app/controllers/wizard/step7_controller.js +++ b/ambari-web/app/controllers/wizard/step7_controller.js @@ -845,11 +845,12 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E var localDB = { hosts: this.get('wizardController.content.hosts'), masterComponentHosts: this.get('wizardController.content.masterComponentHosts'), - slaveComponentHosts: this.get('wizardController.content.slaveComponentHosts'), - selectedStack: {} + slaveComponentHosts: this.get('wizardController.content.slaveComponentHosts') }; + var selectedRepoVersion, repoVersion; + if (this.get('wizardController.name') === 'addServiceController') { repoVersion = App.RepositoryVersion.find().filter(function(i) { return i.get('stackVersionType') === App.get('currentStackName') && @@ -861,9 +862,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E } else { selectedRepoVersion = Em.getWithDefault(App.Stack.find().findProperty('isSelected', true) || {}, 'repositoryVersion', false); } - if (selectedRepoVersion) { - localDB.selectedStack = selectedRepoVersion; - } + var configsByService = {}, dependencies = this.get('configDependencies'); configs.forEach(function (_config) { http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/controllers/wizard/step8_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js index 2a24925..0c72295 100644 --- a/ambari-web/app/controllers/wizard/step8_controller.js +++ b/ambari-web/app/controllers/wizard/step8_controller.js @@ -137,19 +137,34 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz */ configGroups: [], - /** - * List of selected but not installed services - * @type {Object[]} - */ selectedServices: function () { - return this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false); - }.property('[email protected]','[email protected]').cacheable(), + const services = App.StackService.find().map(service => service); + return services; + }.property(), - /** - * List of installed services - * @type {Object[]} - */ - installedServices: Em.computed.filterBy('content.services', 'isInstalled', true), + selectedMpacks: function() { + return this.get('content.selectedMpacks') || this.get('wizardController').getDBProperty('selectedMpacks'); + }.property(), + + downloadConfig: function() { + return this.get('content.downloadConfig') || this.get('wizardController').getDBProperty('downloadConfig'); + }.property(), + + getSelectedStack: function() { + let selectedStack = this.get('content.selectedStack'); + + if (!selectedStack) { + const stack = this.get('wizardController').getDBProperty('selectedStack'); + selectedStack = this.get('wizardController').getStack(stack.stack_name, stack.stack_version); + } + + return selectedStack; + }, + + installedServices: function() { + const services = App.StackService.find().filter(service => service.get('isInstalled') === true); + return services; + }.property(), /** * Current cluster name @@ -301,7 +316,8 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz } } else { // from install wizard - var selectedStack = App.Stack.find().findProperty('isSelected'); + var downloadConfig = this.get('downloadConfig'); + var selectedStack = this.getSelectedStack(); var allRepos = []; if (selectedStack && selectedStack.get('operatingSystems')) { selectedStack.get('operatingSystems').forEach(function (os) { @@ -317,7 +333,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz }, this); } allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName")); - this.get('clusterInfo').set('useRedhatSatellite', selectedStack.get('useRedhatSatellite')); + this.get('clusterInfo').set('useRedhatSatellite', downloadConfig.useRedhatSatellite); this.get('clusterInfo').set('repoInfo', allRepos); } }, @@ -635,7 +651,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz self.set('isBackBtnDisabled', false); wizardController.setStepsEnable(); if (self.get('isAddService')) { - wizardController.setSkipSlavesStep(wizardController.getDBProperty('selectedServiceNames'), 3); + wizardController.setSkipSlavesStep(wizardController.getDBProperty('selectedServiceNames'), 3); //TODO: something } }); } else { @@ -687,14 +703,16 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz // delete any existing clusters to start from a clean slate // before creating a new cluster in install wizard // TODO: modify for multi-cluster support - this.getExistingClusterNames().complete(function () { - var clusterNames = self.get('clusterNames'); - if (self.get('isInstaller') && !App.get('testMode') && clusterNames.length) { - self.deleteClusters(clusterNames); - } else { - self.getExistingVersions(); - } - }); + // this.getExistingClusterNames().complete(function () { + // var clusterNames = self.get('clusterNames'); + // if (self.get('isInstaller') && !App.get('testMode') && clusterNames.length) { + // self.deleteClusters(clusterNames); + // } else { + // self.getExistingVersions(); + // } + // }); + + this.startDeploy(); }, /** @@ -902,28 +920,17 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz * To Start deploy process * @method startDeploy */ + //TODO: mpacks startDeploy: function () { + const self = this; + if (!this.get('isInstaller')) { this._startDeploy(); } else { - var installerController = App.router.get('installerController'); - var versionData = installerController.getSelectedRepoVersionData(); - if (versionData) { - var self = this; - installerController.postVersionDefinitionFileStep8(versionData.isXMLdata, versionData.data).done(function (versionInfo) { - if (versionInfo.id && versionInfo.stackName && versionInfo.stackVersion) { - var selectedStack = App.Stack.find().findProperty('isSelected', true); - if (selectedStack) { - selectedStack.set('versionInfoId', versionInfo.id); - } - installerController.updateRepoOSInfo(versionInfo, selectedStack).done(function() { - self._startDeploy(); - }); - } - }); - } else { - this._startDeploy(); - } + const selectedStack = this.getSelectedStack(); + this.get('wizardController').updateRepoOSInfo({ id: selectedStack.get('id'), stackName: selectedStack.get('stackName'), stackVersion: selectedStack.get('stackVersion') }, selectedStack).done(function() { + self._startDeploy(); + }); } }, @@ -975,13 +982,14 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz * Queued request * @method createCluster */ + //TODO: mpacks createCluster: function () { if (!this.get('isInstaller')) return; - var stackVersion = this.get('content.installOptions.localRepo') ? App.currentStackVersion.replace(/(-\d+(\.\d)*)/ig, "Local$&") : App.currentStackVersion; + const selectedStack = this.getSelectedStack() this.addRequestToAjaxQueue({ name: 'wizard.step8.create_cluster', data: { - data: JSON.stringify({ "Clusters": {"version": stackVersion}}) + data: JSON.stringify({ "Clusters": {"version": selectedStack.get('stackNameVersion')}}) }, success: 'createClusterSuccess' }); @@ -1028,13 +1036,14 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz * @returns {Object[]} * @method createSelectedServicesData */ + //TODO: mpacks createSelectedServicesData: function () { var selectedStack; if (this.get('isInstaller')) { - selectedStack = App.Stack.find().findProperty('isSelected', true); + selectedStack = this.getSelectedStack(); } return this.get('selectedServices').map(service => selectedStack ? - {"ServiceInfo": { "service_name": service.get('serviceName'), "service_type": service.get('serviceName'), "service_group_name": App.get('defaultServiceGroupName'), "desired_repository_version_id": selectedStack.get('versionInfoId') }} : + {"ServiceInfo": { "service_name": service.get('serviceName'), "service_type": service.get('serviceName'), "service_group_name": App.get('defaultServiceGroupName'), "desired_repository_version_id": selectedStack.get('id') }} : {"ServiceInfo": { "service_name": service.get('serviceName'), "service_type": service.get('serviceName'), "service_group_name": App.get('defaultServiceGroupName'), }}); }, @@ -2017,7 +2026,7 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz }, this); }, this); - var selectedStack = App.Stack.find().findProperty('isSelected', true); + var selectedStack = this.getSelectedStack(); blueprint = { 'configurations': totalConf, 'host_groups': host_groups.filter(function (item) { return item.cardinality > 0; }), http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/mappers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js index cde9bcc..38d9c08 100644 --- a/ambari-web/app/mappers.js +++ b/ambari-web/app/mappers.js @@ -19,6 +19,7 @@ //load all mappers require('mappers/server_data_mapper'); require('mappers/stack_service_mapper'); +require('mappers/mpack_service_mapper'); require('mappers/stack_mapper'); require('mappers/stack_version_mapper'); require('mappers/configs/themes_mapper'); @@ -44,4 +45,4 @@ require('mappers/alert_notification_mapper'); require('mappers/root_service_mapper'); require('mappers/widget_mapper'); require('mappers/widget_layout_mapper'); -require('mappers/stack_upgrade_history_mapper'); \ No newline at end of file +require('mappers/stack_upgrade_history_mapper'); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/mappers/mpack_service_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/mpack_service_mapper.js b/ambari-web/app/mappers/mpack_service_mapper.js new file mode 100644 index 0000000..72cffa3 --- /dev/null +++ b/ambari-web/app/mappers/mpack_service_mapper.js @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var App = require('app'); + +App.MpackServiceMapper = App.QuickDataMapper.create({ + model: App.StackService, + component_model: App.StackServiceComponent, + + config: { + id: 'service_name', + stack_id: 'stack_id', + service_name: 'service_name', + service_type: 'service_type', + display_name: 'display_name', + config_types: 'config_types', + comments: 'comments', + service_version: 'service_version', + stack_name: 'stack_name', + stack_version: 'stack_version', + selection: 'selection', + is_mandatory: 'is_mandatory', + is_selected: 'is_selected', + is_installed: 'is_installed', + is_installable: 'is_installable', + is_service_with_widgets: 'is_service_with_widgets', + required_services: 'required_services', + service_check_supported: 'service_check_supported', + support_delete_via_ui: 'support_delete_via_ui', + service_components_key: 'service_components', + service_components_type: 'array', + service_components: { + item: 'id' + } + }, + + component_config: { + id: 'component_name', + component_name: 'component_name', + display_name: 'display_name', + cardinality: 'cardinality', + custom_commands: 'custom_commands', + reassign_allowed : 'reassign_allowed', + decommission_allowed: 'decommission_allowed', + has_bulk_commands_definition: 'has_bulk_commands_definition', + bulk_commands_display_name: 'bulk_commands_display_name', + bulk_commands_master_component_name: 'bulk_commands_master_component_name', + service_name: 'service_name', + component_category: 'component_category', + rolling_restart_supported: 'rolling_restart_supported', + is_master: 'is_master', + is_client: 'is_client', + stack_name: 'stack_name', + stack_version: 'stack_version', + stack_service_id: 'service_name', + dependencies_key: 'dependencies', + dependencies_type: 'array', + dependencies: { + item: 'Dependencies' + } + }, + + map: function (service) { + var model = this.get('model'); + var result = []; + var stackServiceComponents = []; + var nonInstallableServices = ['KERBEROS']; + var displayOrderLength = App.StackService.displayOrder.length; + var stackService = service.StackServices; + var serviceComponents = []; + service.components.forEach(function (serviceComponent) { + var dependencies = serviceComponent.dependencies.map(function (dependecy) { + return { Dependencies: App.keysUnderscoreToCamelCase(App.permit(dependecy.Dependencies, ['component_name', 'scope', 'service_name'])) }; + }); + serviceComponent.StackServiceComponents.id = serviceComponent.StackServiceComponents.component_name; + serviceComponent.StackServiceComponents.dependencies = dependencies; + serviceComponents.push(serviceComponent.StackServiceComponents); + var parsedResult = this.parseIt(serviceComponent.StackServiceComponents, this.get('component_config')); + if (parsedResult.id == 'MYSQL_SERVER') { + parsedResult.custom_commands = parsedResult.custom_commands.without('CLEAN'); + } + stackServiceComponents.push(parsedResult); + }, this); + stackService.stack_id = stackService.stack_name + '-' + stackService.stack_version; + stackService.service_components = serviceComponents; + stackService.is_service_with_widgets = service.artifacts.someProperty('Artifacts.artifact_name', 'widgets_descriptor'); + // @todo: replace with server response value after API implementation + if (nonInstallableServices.contains(stackService.service_name)) { + stackService.is_installable = false; + stackService.is_selected = false; + } + if(stackService.selection === "MANDATORY") { + stackService.is_mandatory = true; + } + result.push(this.parseIt(stackService, this.get('config'))); + + App.store.safeLoadMany(this.get('component_model'), stackServiceComponents); + App.store.safeLoadMany(model, result); + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/mappers/stack_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/stack_mapper.js b/ambari-web/app/mappers/stack_mapper.js index 07fb137..415845e 100644 --- a/ambari-web/app/mappers/stack_mapper.js +++ b/ambari-web/app/mappers/stack_mapper.js @@ -22,7 +22,7 @@ App.stackMapper = App.QuickDataMapper.create({ modelOS: App.OperatingSystem, modelRepo: App.Repository, modelServices: App.ServiceSimple, - + configStack: { id: 'id', stack_name: 'stack_name', @@ -51,7 +51,7 @@ App.stackMapper = App.QuickDataMapper.create({ item: 'id' } }, - + configOS: { id: 'id', os_type: 'os_type', @@ -72,7 +72,7 @@ App.stackMapper = App.QuickDataMapper.create({ display_name: 'display_name', latest_version: 'latest_version' }, - + configRepository: { id: 'id', base_url: 'base_url', @@ -89,7 +89,7 @@ App.stackMapper = App.QuickDataMapper.create({ components: 'components', distribution: 'distribution' }, - + map: function(json) { var modelStack = this.get('modelStack'); var modelOS = this.get('modelOS'); @@ -104,6 +104,7 @@ App.stackMapper = App.QuickDataMapper.create({ if (!stack.id) { stack.id = stack.stack_name + '-' + stack.stack_version + '-' + stack.repository_version; //HDP-2.5-2.5.0.0 } + var operatingSystemsArray = []; var servicesArray = []; @@ -125,7 +126,7 @@ App.stackMapper = App.QuickDataMapper.create({ operatingSystems.is_selected = ops.isSelected == true || ops.isSelected == undefined; resultOS.push(this.parseIt(operatingSystems, this.get('configOS'))); operatingSystemsArray.pushObject(operatingSystems); - + }, this); stack.stack_services.forEach(function(service) { http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index f74c560..bb8b218 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -597,6 +597,12 @@ Em.I18n.translations = { 'installer.controls.serviceConfigMasterHosts.header':'{0} Hosts', 'installer.controls.slaveComponentChangeGroupName.error':'group with this name already exist', + 'installer.selectMpacks.loadSelectionFailed': 'Could not load Management Packs. The software registry may not be available.', + 'installer.selectMpacks.header': 'Select Management Packs', + 'installer.selectMpacks.body.header': 'Select Management Packs', + 'installer.selectMpacks.noMpacksAvailable': 'No management packs are available.', + 'installer.selectMpacks.noMpacksSelected': 'Select from the list of available products.', + 'installer.step0.header':'Get Started', 'installer.step0.body.header':'Get Started', 'installer.step0.body':'This wizard will walk you through the cluster installation process. First, start by naming your new cluster.', http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/mixins/wizard/wizard_menu_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/wizard/wizard_menu_view.js b/ambari-web/app/mixins/wizard/wizard_menu_view.js index c2959e9..6dd7394 100644 --- a/ambari-web/app/mixins/wizard/wizard_menu_view.js +++ b/ambari-web/app/mixins/wizard/wizard_menu_view.js @@ -34,7 +34,13 @@ App.WizardMenuMixin = Em.Mixin.create({ isStepDisabled: function (stepName) { let index = this.get('controller').getStepIndex(stepName); - return this.get('controller.isStepDisabled').findProperty('step', index).get('value'); + let step = this.get('controller.isStepDisabled').findProperty('step', index); + + if (step) { + return step.get('value'); + } + + return false; }, isStepCompleted(stepName) { @@ -48,6 +54,7 @@ App.WizardMenuMixin = Em.Mixin.create({ isStep3Disabled: isStepDisabled("step3"), isConfigureDownloadDisabled: isStepDisabled("configureDownload"), isDownloadProductsDisabled: isStepDisabled("downloadProducts"), + isSelectMpacksDisabled: isStepDisabled("selectMpacks"), isStep4Disabled: isStepDisabled("step4"), isStep5Disabled: isStepDisabled("step5"), isStep6Disabled: isStepDisabled("step6"), @@ -62,6 +69,7 @@ App.WizardMenuMixin = Em.Mixin.create({ isStep3Completed: isStepCompleted("step3"), isConfigureDownloadCompleted: isStepCompleted("configureDownload"), isDownloadProductsCompleted: isStepCompleted("downloadProducts"), + isSelectMpacksCompleted: isStepCompleted("selectMpacks"), isStep4Completed: isStepCompleted("step4"), isStep5Completed: isStepCompleted("step5"), isStep6Completed: isStepCompleted("step6"), http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/models/stack.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/stack.js b/ambari-web/app/models/stack.js index 657ee5c..1fbc329 100644 --- a/ambari-web/app/models/stack.js +++ b/ambari-web/app/models/stack.js @@ -34,8 +34,6 @@ App.Stack = DS.Model.extend({ operatingSystems: DS.hasMany('App.OperatingSystem'), isSelected: DS.attr('boolean', {defaultValue: false}), - versionInfoId: null, - stackNameVersion: Em.computed.concat('-', 'stackName', 'stackVersion'), isPatch: Em.computed.equal('type', 'PATCH'), http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/router.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js index c2d2a75..d0b1714 100644 --- a/ambari-web/app/router.js +++ b/ambari-web/app/router.js @@ -45,7 +45,9 @@ App.WizardRoute = Em.Route.extend({ gotoConfigureDownload: Em.Router.transitionTo('configureDownload'), - gotoDownloadProducts: Em.Router.transitionTo('configureDownload'), + gotoSelectMpacks: Em.Router.transitionTo('selectMpacks'), + + gotoDownloadProducts: Em.Router.transitionTo('downloadProducts'), isRoutable: function() { return typeof this.get('route') === 'string' && App.router.get('loggedIn'); @@ -208,7 +210,7 @@ App.Router = Em.Router.extend({ } else { newStep = step; } - + var previousStep = parseInt(this.getInstallerCurrentStep(), 10); this.set('isFwdNavigation', newStep >= previousStep); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/routes/installer.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js index 5c3d806..5899ff3 100644 --- a/ambari-web/app/routes/installer.js +++ b/ambari-web/app/routes/installer.js @@ -119,66 +119,66 @@ module.exports = Em.Route.extend(App.RouterRedirections, { } }), - step1: Em.Route.extend({ - route: '/step1', - connectOutlets: function (router) { - console.time('step1 connectOutlets'); - var self = this; - var controller = router.get('installerController'); - var wizardStep1Controller = router.get('wizardStep1Controller'); - wizardStep1Controller.set('skipValidationChecked', false); - wizardStep1Controller.set('optionsToSelect', { - 'usePublicRepo': { - index: 0, - isSelected: true - }, - 'useLocalRepo': { - index: 1, - isSelected: false, - 'uploadFile': { - index: 0, - name: 'uploadFile', - file: '', - hasError: false, - isSelected: true - }, - 'enterUrl': { - index: 1, - name: 'enterUrl', - url: '', - placeholder: Em.I18n.t('installer.step1.useLocalRepo.enterUrl.placeholder'), - hasError: false, - isSelected: false - } - } - }); - controller.setCurrentStep('step1'); - controller.loadAllPriorSteps().done(function () { - wizardStep1Controller.set('wizardController', controller); - controller.connectOutlet('wizardStep1', controller.get('content')); - self.scrollTop(); - console.timeEnd('step1 connectOutlets'); - }); - }, - back: Em.Router.transitionTo('downloadProducts'), - next: function (router) { - console.time('step1 next'); - if(router.get('btnClickInProgress')) { - return; - } - var wizardStep1Controller = router.get('wizardStep1Controller'); - var installerController = router.get('installerController'); - installerController.validateJDKVersion(function() { - installerController.checkRepoURL(wizardStep1Controller).done(function () { - App.set('router.nextBtnClickInProgress', true); - installerController.setDBProperty('service', undefined); - installerController.setStacks(); - router.transitionTo('step4'); - console.timeEnd('step1 next'); - }); - }, function() {}); - } - }), + // step1: Em.Route.extend({ + // route: '/step1', + // connectOutlets: function (router) { + // console.time('step1 connectOutlets'); + // var self = this; + // var controller = router.get('installerController'); + // var wizardStep1Controller = router.get('wizardStep1Controller'); + // wizardStep1Controller.set('skipValidationChecked', false); + // wizardStep1Controller.set('optionsToSelect', { + // 'usePublicRepo': { + // index: 0, + // isSelected: true + // }, + // 'useLocalRepo': { + // index: 1, + // isSelected: false, + // 'uploadFile': { + // index: 0, + // name: 'uploadFile', + // file: '', + // hasError: false, + // isSelected: true + // }, + // 'enterUrl': { + // index: 1, + // name: 'enterUrl', + // url: '', + // placeholder: Em.I18n.t('installer.step1.useLocalRepo.enterUrl.placeholder'), + // hasError: false, + // isSelected: false + // } + // } + // }); + // controller.setCurrentStep('step1'); + // controller.loadAllPriorSteps().done(function () { + // wizardStep1Controller.set('wizardController', controller); + // controller.connectOutlet('wizardStep1', controller.get('content')); + // self.scrollTop(); + // console.timeEnd('step1 connectOutlets'); + // }); + // }, + // back: Em.Router.transitionTo('selectMpacks'), + // next: function (router) { + // console.time('step1 next'); + // if(router.get('btnClickInProgress')) { + // return; + // } + // var wizardStep1Controller = router.get('wizardStep1Controller'); + // var installerController = router.get('installerController'); + // installerController.validateJDKVersion(function() { + // installerController.checkRepoURL(wizardStep1Controller).done(function () { + // App.set('router.nextBtnClickInProgress', true); + // installerController.setDBProperty('service', undefined); + // installerController.setStacks(); + // router.transitionTo('step4'); + // console.timeEnd('step1 next'); + // }); + // }, function() {}); + // } + // }), step2: Em.Route.extend({ route: '/step2', @@ -262,7 +262,6 @@ module.exports = Em.Route.extend(App.RouterRedirections, { } }), - configureDownload: Em.Route.extend({ route: '/configureDownload', connectOutlets: function (router) { @@ -272,31 +271,6 @@ module.exports = Em.Route.extend(App.RouterRedirections, { var configureDownloadController = router.get('wizardConfigureDownloadController'); var newStepIndex = controller.getStepIndex('configureDownload'); router.setNavigationFlow(newStepIndex); - configureDownloadController.set('optionsToSelect', { - 'usePublicRepo': { - index: 0, - isSelected: true - }, - 'useLocalRepo': { - index: 1, - isSelected: false, - 'uploadFile': { - index: 0, - name: 'uploadFile', - file: '', - hasError: false, - isSelected: true - }, - 'enterUrl': { - index: 1, - name: 'enterUrl', - url: '', - placeholder: Em.I18n.t('installer.step1.useLocalRepo.enterUrl.placeholder'), - hasError: false, - isSelected: false - } - } - }); controller.setCurrentStep('configureDownload'); controller.loadAllPriorSteps().done(function () { configureDownloadController.set('wizardController', controller); @@ -312,11 +286,44 @@ module.exports = Em.Route.extend(App.RouterRedirections, { return; } App.set('router.nextBtnClickInProgress', true); - router.transitionTo('downloadProducts'); + var installerController = router.get('installerController'); + installerController.setDBProperty('service', undefined); + router.transitionTo('selectMpacks'); console.timeEnd('configureDownload next'); } }), + selectMpacks: App.StepRoute.extend({ + route: '/selectMpacks', + breadcrumbs: { label: Em.I18n.translations['installer.selectMpacks.header'] }, + connectOutlets: function (router) { + console.time('selectMpacks connectOutlets'); + var self = this; + var controller = router.get('installerController'); + controller.setCurrentStep('selectMpacks'); + controller.loadAllPriorSteps().done(function () { + var wizardSelectMpacksController = router.get('wizardSelectMpacksController'); + wizardSelectMpacksController.set('wizardController', controller); + controller.connectOutlet('wizardSelectMpacks', controller.get('content')); + self.scrollTop(); + console.timeEnd('selectMpacks connectOutlets'); + }); + }, + + backTransition: function (router) { + router.transitionTo('configureDownload'); + }, + + next: function (router, context) { + console.time('selectMpacks next'); + if (!router.get('btnClickInProgress')) { + App.set('router.nextBtnClickInProgress', true); + router.transitionTo('downloadProducts'); + console.timeEnd('selectMpacks next'); + } + }, + }), + downloadProducts: App.StepRoute.extend({ route: '/downloadProducts', connectOutlets: function (router) { @@ -336,7 +343,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, { }, backTransition: function (router) { - router.transitionTo('configureDownload'); + router.transitionTo('selectMpacks'); }, next: function (router) { @@ -345,7 +352,14 @@ module.exports = Em.Route.extend(App.RouterRedirections, { return; } App.set('router.nextBtnClickInProgress', true); - router.transitionTo('step1'); + router.get('wizardStep5Controller').clearRecommendations(); // Force reload recommendation before step 5 + var controller = router.get('installerController'); + controller.setDBProperties({ + recommendations: undefined, + masterComponentHosts: undefined + }); + controller.clearEnhancedConfigs(); + router.transitionTo('step5'); console.timeEnd('downloadProducts next'); } }), @@ -414,7 +428,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, { }); }, backTransition: function(router) { - router.transitionTo('step4'); + router.transitionTo('downloadProducts'); }, next: function (router) { console.time('step5 next'); @@ -695,6 +709,10 @@ module.exports = Em.Route.extend(App.RouterRedirections, { gotoStep10: Em.Router.transitionTo('step10'), - gotoConfigureDownload: Em.Router.transitionTo('configureDownload') + gotoConfigureDownload: Em.Router.transitionTo('configureDownload'), + + gotoSelectMpacks: Em.Router.transitionTo('selectMpacks'), + + gotoDownloadProducts: Em.Router.transitionTo('downloadProducts') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/templates/installer.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/installer.hbs b/ambari-web/app/templates/installer.hbs index 20cf109..47e63cc 100644 --- a/ambari-web/app/templates/installer.hbs +++ b/ambari-web/app/templates/installer.hbs @@ -29,15 +29,14 @@ <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep2:active view.isStep2Disabled:disabled view.isStep2Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep2 target="controller"}}><i class="step-marker"><span class="step-index">1</span></i><p class="step-name">{{t installer.step2.header}}</p></a></li> <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep3:active view.isStep3Disabled:disabled view.isStep3Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep3 target="controller"}}><i class="step-marker"><span class="step-index">2</span></i><p class="step-name">{{t installer.step3.header}}</p></a></li> <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isConfigureDownload:active view.isConfigureDownloadDisabled:disabled view.isConfigureDownloadCompleted:completed"}}><a href="javascript:void(null);" {{action gotoConfigureDownload target="controller"}}><i class="step-marker"><span class="step-index">3</span></i><p class="step-name">{{t installer.configureDownload.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isDownloadProducts:active view.isDownloadProductsDisabled:disabled view.isDownloadProductsCompleted:completed"}}><a href="javascript:void(null);" {{action gotoDownloadProducts target="controller"}}><i class="step-marker"><span class="step-index">4</span></i><p class="step-name">{{t installer.downloadProducts.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep1:active view.isStep1Disabled:disabled view.isStep1Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep1 target="controller"}}><i class="step-marker"><span class="step-index">5</span></i><p class="step-name">{{t installer.step1.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep4:active view.isStep4Disabled:disabled view.isStep4Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep4 target="controller"}}><i class="step-marker"><span class="step-index">6</span></i><p class="step-name">{{t installer.step4.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep5:active view.isStep5Disabled:disabled view.isStep5Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep5 target="controller"}}><i class="step-marker"><span class="step-index">7</span></i><p class="step-name">{{t installer.step5.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep6:active view.isStep6Disabled:disabled view.isStep6Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep6 target="controller"}}><i class="step-marker"><span class="step-index">8</span></i><p class="step-name">{{t installer.step6.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep7:active view.isStep7Disabled:disabled view.isStep7Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep7 target="controller"}}><i class="step-marker"><span class="step-index">9</span></i><p class="step-name">{{t installer.step7.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep8:active view.isStep8Disabled:disabled view.isStep8Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep8 target="controller"}}><i class="step-marker"><span class="step-index">10</span></i><p class="step-name">{{t installer.step8.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep9:active view.isStep9Disabled:disabled view.isStep9Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep9 target="controller"}}><i class="step-marker"><span class="step-index">11</span></i><p class="step-name">{{t installer.step9.header}}</p></a></li> - <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep10:active view.isStep10Disabled:disabled view.isStep10Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep10 target="controller"}}><i class="step-marker"><span class="step-index">12</span></i><p class="step-name">{{t installer.step10.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isSelectMpacks:active view.isSelectMpacksDisabled:disabled view.isSelectMpacksCompleted:completed"}}><a href="javascript:void(null);" {{action gotoSelectMpacks target="controller"}}><i class="step-marker"><span class="step-index">4</span></i><p class="step-name">{{t installer.selectMpacks.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isDownloadProducts:active view.isDownloadProductsDisabled:disabled view.isDownloadProductsCompleted:completed"}}><a href="javascript:void(null);" {{action gotoDownloadProducts target="controller"}}><i class="step-marker"><span class="step-index">5</span></i><p class="step-name">{{t installer.downloadProducts.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep5:active view.isStep5Disabled:disabled view.isStep5Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep5 target="controller"}}><i class="step-marker"><span class="step-index">6</span></i><p class="step-name">{{t installer.step5.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep6:active view.isStep6Disabled:disabled view.isStep6Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep6 target="controller"}}><i class="step-marker"><span class="step-index">7</span></i><p class="step-name">{{t installer.step6.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep7:active view.isStep7Disabled:disabled view.isStep7Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep7 target="controller"}}><i class="step-marker"><span class="step-index">8</span></i><p class="step-name">{{t installer.step7.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep8:active view.isStep8Disabled:disabled view.isStep8Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep8 target="controller"}}><i class="step-marker"><span class="step-index">9</span></i><p class="step-name">{{t installer.step8.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep9:active view.isStep9Disabled:disabled view.isStep9Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep9 target="controller"}}><i class="step-marker"><span class="step-index">10</span></i><p class="step-name">{{t installer.step9.header}}</p></a></li> + <li {{QAAttr "wizard-nav-step"}} {{bindAttr class="isStep10:active view.isStep10Disabled:disabled view.isStep10Completed:completed"}}><a href="javascript:void(null);" {{action gotoStep10 target="controller"}}><i class="step-marker"><span class="step-index">11</span></i><p class="step-name">{{t installer.step10.header}}</p></a></li> </ul> </div> {{! outlet includes body and footer }} http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/templates/wizard/configureDownload.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/wizard/configureDownload.hbs b/ambari-web/app/templates/wizard/configureDownload.hbs index d178fcf..c28660e 100644 --- a/ambari-web/app/templates/wizard/configureDownload.hbs +++ b/ambari-web/app/templates/wizard/configureDownload.hbs @@ -20,43 +20,36 @@ <div class="panel panel-default"> <div class="panel-body"> - {{#if isLoadingComplete}} - {{! left tabs }} - - {{#if App.router.nextBtnClickInProgress}} - {{view App.SpinnerView}} - {{else}} - <form id="repoVersionInfoForm" class="form-horizontal" role="form" name="localVersionInfoForm" novalidate> - - <div class="panel panel-default repos-panel"> - <div class="step-title"> - <p>{{t installer.configureDownload.body.title}}</p> - </div> - <p class="step-description">{{t installer.configureDownload.body.description}}</p> - <div class="panel-body version-contents-body"> - <div class="row radio-group"> - {{! Public Repository radio }} - <div {{bindAttr class=":col-sm-4 :radio :big-radio :public-radio :wizard-plain-text"}} {{action usePublicRepo target="controller"}}> - {{view view.usePublicRepoRadioButton classNames="repo-checkbox" labelIdentifier="use-public-repo"}} - <p>{{t installer.configureDownload.publicRepo.hoverDesc}}</p> - <i class="icon icon-cloud-download"></i> - <div class="repo-group">{{t installer.configureDownload.publicRepo}}</div> - </div> - {{!--Local repo radio--}} - {{!--Not allowing any action on Local Repository for the first iteration. Will use action useLocalRepo later when this option is allowed--}} - <div {{bindAttr class=":col-sm-4 :radio :big-radio :local-radio :wizard-plain-text"}}> - {{view view.useLocalRepoRadioButton classNames="repo-checkbox" labelIdentifier="use-local-repo"}} - <p>{{t installer.configureDownload.localRepo.hoverDesc}}</p> - <i class="icon icon-tasks"></i> - <div class="repo-group">{{t installer.configureDownload.localRepo}}</div> - </div> + {{#if App.router.nextBtnClickInProgress}} + {{view App.SpinnerView}} + {{else}} + <form id="repoVersionInfoForm" class="form-horizontal" role="form" name="localVersionInfoForm" novalidate> + <div class="panel panel-default repos-panel"> + <div class="step-title"> + <p>{{t installer.configureDownload.body.title}}</p> + </div> + <p class="step-description">{{t installer.configureDownload.body.description}}</p> + <div class="panel-body version-contents-body"> + <div class="row radio-group"> + {{! Public Repository radio }} + <div {{bindAttr class=":col-sm-4 :radio :big-radio :public-radio :wizard-plain-text"}} {{action usePublicRepo target="controller"}}> + {{view view.usePublicRepoRadioButton classNames="repo-checkbox" labelIdentifier="use-public-repo"}} + <p>{{t installer.configureDownload.publicRepo.hoverDesc}}</p> + <i class="icon icon-cloud-download"></i> + <div class="repo-group">{{t installer.configureDownload.publicRepo}}</div> + </div> + {{!--Local repo radio--}} + {{!--Not allowing any action on Local Repository for the first iteration. Will use action useLocalRepo later when this option is allowed--}} + <div {{bindAttr class=":col-sm-4 :radio :big-radio :local-radio :wizard-plain-text"}}> + {{view view.useLocalRepoRadioButton classNames="repo-checkbox" labelIdentifier="use-local-repo"}} + <p>{{t installer.configureDownload.localRepo.hoverDesc}}</p> + <i class="icon icon-tasks"></i> + <div class="repo-group">{{t installer.configureDownload.localRepo}}</div> </div> </div> </div> - </form> - {{/if}} - {{else}} - {{view App.SpinnerView}} + </div> + </form> {{/if}} </div> </div> @@ -68,7 +61,7 @@ {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} {{/if}} </button> - <button type="button" class="btn btn-success pull-right" {{bindAttr disabled="view.isSubmitDisabled"}} {{action next}} {{QAAttr "wizard-next"}}> + <button type="button" class="btn btn-success pull-right" {{bindAttr disabled="view.isSubmitDisabled"}} {{action submit target="controller"}} {{QAAttr "wizard-next"}}> {{#if App.router.nextBtnClickInProgress}} {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} {{/if}} http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/ambari-web/app/templates/wizard/downloadProducts.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/wizard/downloadProducts.hbs b/ambari-web/app/templates/wizard/downloadProducts.hbs index 25be35d..a426225 100644 --- a/ambari-web/app/templates/wizard/downloadProducts.hbs +++ b/ambari-web/app/templates/wizard/downloadProducts.hbs @@ -88,10 +88,10 @@ {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} {{/if}} </button> - <button type="button" class="btn btn-success pull-right" {{bindAttr disabled="view.isSubmitDisabled"}} {{action next}} {{QAAttr "wizard-next"}}> + <button type="button" class="btn btn-success pull-right" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}} {{QAAttr "wizard-next"}}> {{#if App.router.nextBtnClickInProgress}} {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} {{/if}} {{t common.next}} → </button> -</div> \ No newline at end of file +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/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 new file mode 100644 index 0000000..b325b8c --- /dev/null +++ b/ambari-web/app/templates/wizard/selectMpacks.hbs @@ -0,0 +1,70 @@ +{{! +* 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 id="select-mpacks" class="wizard-content col-md-9"> + <h4 class="step-title">{{t installer.selectMpacks.body.header}}</h4> + + <div class="panel panel-default"> + <div class="panel-body"> + <!-- Registry --> + <div class="col-md-6"> + <div class="panel panel-default"> + <div class="panel-body"> + {{#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> + + <!-- Selection --> + <div class="col-md-6"> + <div class="panel panel-default"> + <div class="panel-body"> + {{#if controller.hasSelectedMpackVersions}} + {{#each mpackVersion in controller.selectedMpackVersions}} + {{view App.WizardSelectedMpackVersionView mpackVersionBinding="mpackVersion"}} + {{/each}} + {{else}} + {{t installer.selectMpacks.noMpacksSelected}} + {{/if}} + </div> + </div> + </div> + + </div> + </div> +</div> + +<div class="wizard-footer col-md-12"> + <button type="button" class="btn btn-default pull-left installer-back-btn" {{bindAttr disabled="App.router.btnClickInProgress"}} {{action back}} {{QAAttr "wizard-back"}}> + ← {{t common.back}} + {{#if App.router.backBtnClickInProgress}} + {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} + {{/if}} + </button> + <button type="button" class="btn btn-success pull-right" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}} {{QAAttr "wizard-next"}}> + {{#if App.router.nextBtnClickInProgress}} + {{view App.SpinnerView tagName="span" classNames="service-button-spinner"}} + {{/if}} + {{t common.next}} → + </button> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/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 new file mode 100644 index 0000000..0f24859 --- /dev/null +++ b/ambari-web/app/templates/wizard/selectMpacks/mpack.hbs @@ -0,0 +1,31 @@ +{{! +* 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="panel panel-default"> + <div class="panel-heading" role="tab" id="headingOne"> + <h4 class="panel-title">{{mpack.name}} {{view.version}}</h4> + <p>{{mpack.description}}</p> + </div> + <div> + {{#each service in view.services}} + <button {{bindAttr id="service.name"}} class="btn-service" {{action "selectService" service.id target="controller"}}> + {{service.name}} + <span {{bindAttr class="selected:service-remove:service-add"}} {{bindAttr title="service.version"}}></span> + </button> + {{/each}} + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/15347746/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 new file mode 100644 index 0000000..8b24c25 --- /dev/null +++ b/ambari-web/app/templates/wizard/selectMpacks/selectedMpackVersion.hbs @@ -0,0 +1,32 @@ +{{! +* 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="panel panel-default"> + <div class="panel-heading" role="tab" id="headingOne"> + <h4 class="panel-title">{{mpackVersion.mpack.name}} {{mpackVersion.version}}</h4> + </div> + <div> + {{#each service in mpackVersion.services}} + {{#if service.selected}} + <button {{bindAttr id="service.name"}} class="btn-service" {{action "removeService" service.id target="controller"}}> + {{service.name}} + <span {{bindAttr class="selected:service-remove:service-add" title="service.version"}}></span> + </button> + {{/if}} + {{/each}} + </div> +</div>
