AMBARI-7334. Slider View: Show view name along with hover of view properties. (onechiporenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/42a5a334 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/42a5a334 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/42a5a334 Branch: refs/heads/branch-alerts-dev Commit: 42a5a33497e432f3d7f258f7070eeeaf20beb2a8 Parents: 460ae9e Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Tue Sep 16 18:01:26 2014 +0300 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Tue Sep 16 18:01:26 2014 +0300 ---------------------------------------------------------------------- .../ui/app/controllers/slider_controller.js | 104 +++++++++++++---- .../src/main/resources/ui/app/initialize.js | 31 +++-- .../ui/app/mappers/application_status.js | 115 ------------------- .../resources/ui/app/styles/application.less | 8 ++ .../resources/ui/app/templates/application.hbs | 4 +- .../ui/app/templates/slider_title_tooltip.hbs | 27 +++++ .../src/main/resources/ui/app/translations.js | 2 +- .../resources/ui/app/views/application_view.js | 64 +++++++++++ 8 files changed, 207 insertions(+), 148 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/controllers/slider_controller.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/controllers/slider_controller.js b/contrib/views/slider/src/main/resources/ui/app/controllers/slider_controller.js index 8283de1..a5eec96 100644 --- a/contrib/views/slider/src/main/resources/ui/app/controllers/slider_controller.js +++ b/contrib/views/slider/src/main/resources/ui/app/controllers/slider_controller.js @@ -29,29 +29,36 @@ * If Slider-properties exists: * - Load cluster name * - Load hostNames + * After whole data has been loaded set <code>App.sliderConfigs</code> and enable/disable Slider * @type {Ember.Controller} */ -App.SliderController = Ember.Controller.extend({ +App.SliderController = Ember.Controller.extend(App.RunPeriodically, { /** - * Load resources on controller initialization - * @method initResources + * Map for Slider-errors + * If some config is empty, service isn't installed + * @type {object} */ - initResources: function () { - this.getParametersFromViewProperties(); + serviceConfigMap: { + HDFS: 'hdfsAddress', + YARN: 'yarnResourceManager', + ZOOKEEPER: 'zookeeperQuorum' }, /** * List of Slider-properties mapped from Ambari-configs + * Key-names used in Slider-Title-Popup, so don't change it pls * @type {Em.Object} */ initialValuesToLoad: Em.Object.create({ ambariAddress: null, clusterName: null, hdfsAddress: null, - yarnRMAddress: null, - yarnRMSchedulerAddress: null, - zookeeperQuorum: null + yarnResourceManager: null, + yarnResourceManagerScheduler: null, + zookeeperQuorum: null, + gangliaServer: null, + gangliaClusters: null }), /** @@ -61,6 +68,14 @@ App.SliderController = Ember.Controller.extend({ zookeeperHosts: [], /** + * Load resources on controller initialization + * @method initResources + */ + initResources: function () { + this.getParametersFromViewProperties(); + }, + + /** * Get Slider properties from View-parameters (set in the Ambari Admin View) * If parameters can't be found, use Ambari-configs to populate Slider properties * @returns {$.ajax} @@ -71,20 +86,44 @@ App.SliderController = Ember.Controller.extend({ name: 'slider.getViewParams', sender: this, success: 'getParametersFromViewPropertiesSuccessCallback', - error: 'getClusterName' + error: 'getParametersFromViewPropertiesErrorCallback' }); }, /** * Check if Slider-properties exist + * If exist - set Slider properties using view-configs * If not - get Ambari configs to populate Slider properties * @param {object} data * @method getParametersFromViewPropertiesSuccessCallback */ getParametersFromViewPropertiesSuccessCallback: function(data) { var properties = Em.get(data, 'ViewInstanceInfo.properties'), - loadConfigs = Em.isNone(properties); - this.getClusterName(loadConfigs); + initialValuesToLoad = this.get('initialValuesToLoad'); + if (Em.isEmpty(properties)) { + this.getClusterName(); + } + else { + initialValuesToLoad.setProperties({ + ambariAddress: location.protocol + "//" + document.location.host, + hdfsAddress: properties['hdfs.address'], + yarnResourceManager: properties['yarn.resourcemanager.address'], + yarnResourceManagerScheduler: properties['yarn.resourcemanager.scheduler.address'], + zookeeperQuorum: properties['zookeeper.quorum'], + gangliaServer: properties['ganglia.server.hostname'], + gangliaClusters: properties['ganglia.custom.clusters'] + }); + App.set('gangliaHost', properties['ganglia.server.hostname']); + this.finishSliderConfiguration(); + } + }, + + /** + * Error-callback for Slider-parameters request + * @method getParametersFromViewPropertiesErrorCallback + */ + getParametersFromViewPropertiesErrorCallback: function() { + this.getClusterName(); }, /** @@ -92,14 +131,12 @@ App.SliderController = Ember.Controller.extend({ * @returns {$.ajax} * @method getClusterName */ - getClusterName: function (loadConfigs) { - if (Em.isNone(loadConfigs)) loadConfigs = true; + getClusterName: function () { return App.ajax.send({ name: 'cluster_name', sender: this, data: { - urlPrefix: '/api/v1/', - loadConfigs: loadConfigs + urlPrefix: '/api/v1/' }, success: 'getClusterNameSuccessCallback' }); @@ -119,9 +156,7 @@ App.SliderController = Ember.Controller.extend({ this.loadComponentHost({componentName: "GANGLIA_SERVER", callback: "loadGangliaHostSuccessCallback"}); this.loadComponentHost({componentName: "NAGIOS_SERVER", callback: "loadNagiosHostSuccessCallback"}); this.loadComponentHost({componentName: "ZOOKEEPER_SERVER", callback: "setZookeeperQuorum"}); - if(params.loadConfigs) { - this.loadConfigsTags(); - } + this.loadConfigsTags(); }, /** @@ -182,8 +217,8 @@ App.SliderController = Ember.Controller.extend({ initialValuesToLoad.set('ambariAddress', location.protocol + "//" + document.location.host); initialValuesToLoad.set('clusterName', App.get('clusterName')); initialValuesToLoad.set('hdfsAddress', hdfs.properties['fs.defaultFS']); - initialValuesToLoad.set('yarnRMAddress', yarn.properties['yarn.resourcemanager.address']); - initialValuesToLoad.set('yarnRMSchedulerAddress', yarn.properties['yarn.resourcemanager.scheduler.address']); + initialValuesToLoad.set('yarnResourceManager', yarn.properties['yarn.resourcemanager.address']); + initialValuesToLoad.set('yarnResourceManagerScheduler', yarn.properties['yarn.resourcemanager.scheduler.address']); initialValuesToLoad.set('zookeeperQuorum', zookeeper.properties.clientPort); this.setZookeeperQuorum(); }, @@ -238,14 +273,39 @@ App.SliderController = Ember.Controller.extend({ ViewInstanceInfo: { properties: { 'hdfs.address': initialValues.get('hdfsAddress'), - 'yarn.resourcemanager.address': initialValues.get('yarnRMAddress'), - 'yarn.resourcemanager.scheduler.address': initialValues.get('yarnRMSchedulerAddress'), + 'yarn.resourcemanager.address': initialValues.get('yarnResourceManager'), + 'yarn.resourcemanager.scheduler.address': initialValues.get('yarnResourceManagerScheduler'), 'zookeeper.quorum': initialValues.get('zookeeperQuorum') } } } + }, + success: 'finishSliderConfiguration' + }); + }, + + /** + * After all Slider-configs are loaded, application should check self status + * @method finishSliderConfiguration + */ + finishSliderConfiguration: function() { + //check if all services exist + var serviceConfigMap = this.get('serviceConfigMap'), + initialValuesToLoad = this.get('initialValuesToLoad'), + services = Em.keys(serviceConfigMap), + errors = []; + services.forEach(function(serviceName) { + var configName = Em.get(serviceConfigMap, serviceName); + if (Em.isEmpty(initialValuesToLoad[configName])) { + errors.push(Em.I18n.t('error.no' + serviceName)); } }); + App.setProperties({ + viewErrors: errors, + viewEnabled: errors.length === 0, + sliderConfigs: initialValuesToLoad, + mapperTime: new Date().getTime() + }); }, /** http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/initialize.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/initialize.js b/contrib/views/slider/src/main/resources/ui/app/initialize.js index c9b53d7..fd34ebe 100755 --- a/contrib/views/slider/src/main/resources/ui/app/initialize.js +++ b/contrib/views/slider/src/main/resources/ui/app/initialize.js @@ -60,12 +60,6 @@ App.initializer({ version: viewVersion, /** - * Version of SLIDER_1 resource - * @type {string} - */ - resourcesVersion: '', - - /** * @type {string} */ instance: instanceName, @@ -102,16 +96,35 @@ App.initializer({ * Host with Ganglia Server * @type {string|null} */ - gangliaHost: null + gangliaHost: null, + + /** + * List of Ganglia clusters + * @type {array|null} + */ + gangliaClusters: null, + + /** + * View-configs set from ambari-admin + * Loaded in <code>App.SliderController</code> + * @type {null|object} + */ + sliderConfigs: null, + + /** + * Last time when mapper ran + * @type {null|number} + */ + mapperTime: null }); - application.SliderController.proto().initResources(); + application.SliderController.proto().loop('initResources'); application.ApplicationTypeMapper.loop('load'); application.SliderAppsMapper.loop('load'); } }); -// Load all modules in order automagically. Ember likes things to work this +// Load all modules in order automatically. Ember likes things to work this // way so everything is in the App.* namespace. var folderOrder = [ 'initializers', 'mixins', 'routes', 'models', 'mappers', http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/mappers/application_status.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/mappers/application_status.js b/contrib/views/slider/src/main/resources/ui/app/mappers/application_status.js deleted file mode 100644 index 21e4c55..0000000 --- a/contrib/views/slider/src/main/resources/ui/app/mappers/application_status.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * 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. - */ - -/** - * Mapper for SLIDER_1 status - * Save mapped data to App properties - * @type {App.Mapper} - */ -App.ApplicationStatusMapper = App.Mapper.createWithMixins(App.RunPeriodically, { - - /** - * List of services, we need to get status of them - * @type {Array} - */ - servicesWeNeed: [ - 'HDFS', - 'YARN', - 'ZOOKEEPER' - ], - - /** - * Load data from <code>App.urlPrefix + this.urlSuffix</code> one time - * @method load - * @return {$.ajax} - */ - load: function () { - return App.ajax.send({ - name: 'mapper.applicationStatus', - sender: this, - success: 'setResourcesVersion' - }); - }, - - /** - * Set <code>App</code> properties - * @param {object} data received from server data - * @method setResourcesVersion - */ - setResourcesVersion: function (data) { - App.set('resourcesVersion', Em.getWithDefault(data, "version", 'version')); - if (App.get('clusterName')) { - this.loadServicesStatus(); - } - }, - - /** - * Get Services status from Ambari-server - * @returns {$.ajax} - * @method loadServicesStatus - */ - loadServicesStatus: function () { - return App.ajax.send({ - name: 'service_status', - data: { - urlPrefix: '/api/v1/' - }, - sender: this, - success: 'setErrors' - }); - }, - - /** - * Success-callback for load services status - * Set Slider state basing on <code>ServiceInfo.state</code> - * @param {object} data - * @method setErrors - */ - setErrors: function (data) { - var self = this, - errors = []; - this.get('servicesWeNeed').forEach(function (serviceName) { - var e = self.findError(data.items.findProperty("ServiceInfo.service_name", serviceName)); - if (!Em.isNone(e)) { - errors.push(e); - } - }); - - App.set('viewEnabled', errors.length === 0); - App.set('viewErrors', errors); - }, - - /** - * Get error for service (missed or not started) - * @param {object} data - * @returns {string|null} - */ - findError: function (data) { - var name = Em.get(data, "ServiceInfo.service_name"), - error = null; - if (data) { - if (Em.get(data, "ServiceInfo.state") != "STARTED") - error = Em.I18n.t('error.start' + name); - } - else { - error = Em.I18n.t('error.no' + name); - } - return error; - } - -}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/styles/application.less ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/styles/application.less b/contrib/views/slider/src/main/resources/ui/app/styles/application.less index 33f5555..241a52d 100644 --- a/contrib/views/slider/src/main/resources/ui/app/styles/application.less +++ b/contrib/views/slider/src/main/resources/ui/app/styles/application.less @@ -32,6 +32,14 @@ html { .popover { max-width: 800px; } + +.slider-name-popover { + max-width: 500px !important; + .row { + .table-row(); + } +} + a { cursor: pointer; } http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/templates/application.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/application.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/application.hbs index 1cf3147..439c3a3 100755 --- a/contrib/views/slider/src/main/resources/ui/app/templates/application.hbs +++ b/contrib/views/slider/src/main/resources/ui/app/templates/application.hbs @@ -17,7 +17,9 @@ }} <div> - <h1>{{t slider.apps.title}}</h1> + {{#view view.SliderTitleView}} + <h1>{{t slider.apps.title}} - <span {{bs-bind-popover view.popover}}>{{App.instance}}</span></h1> + {{/view}} </div> {{#if App.viewEnabled}} {{outlet}} http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/templates/slider_title_tooltip.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/slider_title_tooltip.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/slider_title_tooltip.hbs new file mode 100644 index 0000000..3d3e03e --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/templates/slider_title_tooltip.hbs @@ -0,0 +1,27 @@ +{{! +* 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="slider-name-popover"> + <h3><strong>{{App.instance}}</strong></h3> + {{#each config in view.content}} + <div class="row"> + <div class="col-md-4">{{humanize config.name}}</div> + <div class="col-md-8">{{formatWordBreak config.value devider=','}}</div> + </div> + {{/each}} +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/translations.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/translations.js b/contrib/views/slider/src/main/resources/ui/app/translations.js index 51c9352..d7ab3eb 100644 --- a/contrib/views/slider/src/main/resources/ui/app/translations.js +++ b/contrib/views/slider/src/main/resources/ui/app/translations.js @@ -57,7 +57,7 @@ Em.I18n.translations = { 'error.startHDFS': 'Slider applications view requires HDFS service to be started.', 'error.noYARN': 'Slider applications view requires YARN service.', 'error.startYARN': 'Slider applications view requires YARN service to be started.', - 'error.noZooKeeper': 'Slider applications view requires ZooKeeper service.', + 'error.noZOOKEEPER': 'Slider applications view requires ZooKeeper service.', 'error.startZOOKEEPER': 'Slider applications view requires ZooKeeper service to be started.', 'popup.confirmation.commonHeader': 'Confirmation', http://git-wip-us.apache.org/repos/asf/ambari/blob/42a5a334/contrib/views/slider/src/main/resources/ui/app/views/application_view.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/views/application_view.js b/contrib/views/slider/src/main/resources/ui/app/views/application_view.js new file mode 100644 index 0000000..bae82e9 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/views/application_view.js @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +App.ApplicationView = Ember.View.extend({ + + /** + * View with popover for Slider title + * @type {Ember.View} + */ + SliderTitleView: Em.View.extend({ + + /** + * Popover-config + * @type {Em.Object} + */ + popover: Em.Object.create({ + trigger: 'hover', + placement: 'bottom' + }), + + /** + * Set <code>popover</code> template + * @method sliderConfigsChecker + */ + sliderConfigsChecker: function() { + var configs = App.get('sliderConfigs'), + res = [], + excludedConfigs = ['ambariAddress', 'clusterName']; + if (configs) { + Em.keys(configs).forEach(function(c) { + if (!excludedConfigs.contains(c)) { + res.push({name: c, value: configs[c]}); + } + }); + } + this.set('content', res); + var template = this.createChildView(App.SliderTitleTooltipView, { + content: res + }); + this.set('popover.template', template.renderToBuffer().string()); + }.observes('App.mapperTime') + + }) + +}); + +App.SliderTitleTooltipView = Em.View.extend({ + templateName: 'slider_title_tooltip' +});