diff options
author | Yusaku Sako <yusaku@apache.org> | 2012-12-09 14:47:44 +0000 |
---|---|---|
committer | Yusaku Sako <yusaku@apache.org> | 2012-12-09 14:47:44 +0000 |
commit | c357ac4960385fd55240887a6b9b8c0f76d35672 (patch) | |
tree | e57e1c11afbc13a023dcf82ec8857bdfababa942 /ambari-web | |
parent | 5ed4c1c13bc61b69ab0b6733e065d55e81db1504 (diff) |
AMBARI-1059. Refactor cluster management. (yusaku)
git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/AMBARI-666@1418985 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'ambari-web')
53 files changed, 583 insertions, 568 deletions
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js index 0c753a18ea..3f998e0a05 100644 --- a/ambari-web/app/controllers.js +++ b/ambari-web/app/controllers.js @@ -21,6 +21,7 @@ require('controllers/application'); require('controllers/login_controller'); +require('controllers/wizard'); require('controllers/installer'); require('controllers/global/background_operations_controller'); require('controllers/main'); diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js index f8f1fcc062..f215549b00 100644 --- a/ambari-web/app/controllers/global/cluster_controller.js +++ b/ambari-web/app/controllers/global/cluster_controller.js @@ -141,7 +141,7 @@ App.ClusterController = Em.Controller.extend({ } return null; } - }.property('App.router.updateController.isUpdated', 'dataLoadList.hosts'), + }.property('App.router.updateController.isUpdated'), isNagiosInstalled:function () { if (App.testMode) { @@ -157,7 +157,8 @@ App.ClusterController = Em.Controller.extend({ * Sorted list of alerts. * Changes whenever alerts are loaded. */ - alerts:function () { + alerts:[], + updateAlerts: function(){ var alerts = App.Alert.find(); var alertsArray = alerts.toArray(); var sortedArray = alertsArray.sort(function (left, right) { @@ -171,9 +172,8 @@ App.ClusterController = Em.Controller.extend({ } return statusDiff; }); - return sortedArray; - }.property('dataLoadList.alerts'), - + this.set('alerts', sortedArray); + }, loadRuns:function () { if (this.get('postLoadList.runs')) { return; @@ -197,6 +197,9 @@ App.ClusterController = Em.Controller.extend({ * property, which will trigger the alerts property. */ loadAlerts:function () { + if(App.router.get('updateController.isUpdated')){ + return; + } var nagiosUrl = this.get('nagiosUrl'); if (nagiosUrl) { var lastSlash = nagiosUrl.lastIndexOf('/'); @@ -209,10 +212,11 @@ App.ClusterController = Em.Controller.extend({ jsonp:"jsonp", context:this, complete:function (jqXHR, textStatus) { - this.updateLoadStatus('alerts') + this.updateLoadStatus('alerts'); + this.updateAlerts(); }, error: function(jqXHR, testStatus, error) { - this.showMessage(Em.I18n.t('nagios.alerts.unavailable')); + // this.showMessage(Em.I18n.t('nagios.alerts.unavailable')); console.log('Nagios $.ajax() response:', error); } }; diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js index 4e18d223ab..c27251a2f0 100644 --- a/ambari-web/app/controllers/global/update_controller.js +++ b/ambari-web/app/controllers/global/update_controller.js @@ -89,7 +89,7 @@ App.UpdateController = Em.Controller.extend({ updateServiceMetric:function(callback){ var self = this; self.set('isUpdated', false); - var servicesUrl = this.getUrl('/data/dashboard/services.json', '/services?ServiceInfo/service_name!=MISCELLANEOUS&ServiceInfo/service_name!=DASHBOARD&fields=*,components/host_components/*'); + var servicesUrl = this.getUrl('/data/dashboard/services.json', '/services?ServiceInfo/service_name!=MISCELLANEOUS&ServiceInfo/service_name!=DASHBOARD&fields=*,components/host_components/*,components/ServiceComponentInfo'); var callback = callback || function(jqXHR, textStatus){ self.set('isUpdated', true); }; diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js index 78577cf4b0..4b010b9ba3 100644 --- a/ambari-web/app/controllers/installer.js +++ b/ambari-web/app/controllers/installer.js @@ -19,205 +19,12 @@ var App = require('app'); -App.InstallerController = Em.Controller.extend({ +App.InstallerController = App.WizardController.extend({ name: 'installerController', - isStepDisabled: [], - totalSteps: 10, - init: function () { - this.clusters = App.Cluster.find(); - this.isStepDisabled.pushObject(Ember.Object.create({ - step: 1, - value: false - })); - for (var i = 2; i <= this.totalSteps; i++) { - this.isStepDisabled.pushObject(Ember.Object.create({ - step: i, - value: true - })); - } - // window.onbeforeunload = function () { - // return "You have not saved your document yet. If you continue, your work will not be saved." - //} - }, - - setStepsEnable: function () { - for (var i = 2; i <= this.totalSteps; i++) { - var step = this.get('isStepDisabled').findProperty('step', i); - if (i <= this.get('currentStep')) { - step.set('value', false); - } else { - step.set('value', true); - } - } - }.observes('currentStep'), - - setLowerStepsDisable: function (stepNo) { - for (var i = 1; i < stepNo; i++) { - var step = this.get('isStepDisabled').findProperty('step', i); - step.set('value', true); - } - }, - - prevInstallStatus: function () { - console.log('Inside the prevInstallStep function: The name is ' + App.router.get('loginController.loginName')); - var result = App.db.isCompleted() - if (result == '1') { - return true; - } - }.property('App.router.loginController.loginName'), - - /** - * Set current step to new value. - * Method moved from App.router.setInstallerCurrentStep - * @param currentStep - * @param completed - */ - currentStep: function () { - return App.get('router').getWizardCurrentStep('installer'); - }.property(), - - /** - * Set current step to new value. - * Method moved from App.router.setInstallerCurrentStep - * @param currentStep - * @param completed - */ - setCurrentStep: function (currentStep, completed) { - App.db.setWizardCurrentStep('installer', currentStep, completed); - this.set('currentStep', currentStep); - }, - - clusters: null, - - isStep1: function () { - return this.get('currentStep') == 1; - }.property('currentStep'), - - isStep2: function () { - return this.get('currentStep') == 2; - }.property('currentStep'), - - isStep3: function () { - return this.get('currentStep') == 3; - }.property('currentStep'), - - isStep4: function () { - return this.get('currentStep') == 4; - }.property('currentStep'), - - isStep5: function () { - return this.get('currentStep') == 5; - }.property('currentStep'), - - isStep6: function () { - return this.get('currentStep') == 6; - }.property('currentStep'), - - isStep7: function () { - return this.get('currentStep') == 7; - }.property('currentStep'), - - isStep8: function () { - return this.get('currentStep') == 8; - }.property('currentStep'), - - isStep9: function () { - return this.get('currentStep') == 9; - }.property('currentStep'), - - isStep10: function () { - return this.get('currentStep') == 10; - }.property('currentStep'), - - gotoStep1: function () { - if (this.get('isStepDisabled').findProperty('step', 1).get('value') === true) { - return; - } else { - App.router.send('gotoStep1'); - } - - }, - - gotoStep2: function () { - if (this.get('isStepDisabled').findProperty('step', 2).get('value') === true) { - return; - } else { - App.router.send('gotoStep2'); - } - - }, - - gotoStep3: function () { - if (this.get('isStepDisabled').findProperty('step', 3).get('value') === true) { - return; - } else { - App.router.send('gotoStep3'); - } - - }, - - gotoStep4: function () { - - if (this.get('isStepDisabled').findProperty('step', 4).get('value') === true) { - return; - } else { - App.router.send('gotoStep4'); - } - }, - - gotoStep5: function () { - if (this.get('isStepDisabled').findProperty('step', 5).get('value') === true) { - return; - } else { - App.router.send('gotoStep5'); - } - }, - - gotoStep6: function () { - if (this.get('isStepDisabled').findProperty('step', 6).get('value') === true) { - return; - } else { - App.router.send('gotoStep6'); - } - - }, - - gotoStep7: function () { - if (this.get('isStepDisabled').findProperty('step', 7).get('value') === true) { - return; - } else { - App.router.send('gotoStep7'); - } - }, - - gotoStep8: function () { - if (this.get('isStepDisabled').findProperty('step', 8).get('value') === true) { - return; - } else { - App.router.send('gotoStep8'); - } - }, - - gotoStep9: function () { - if (this.get('isStepDisabled').findProperty('step', 9).get('value') === true) { - return; - } else { - App.router.send('gotoStep9'); - } - }, - - gotoStep10: function () { - if (this.get('isStepDisabled').findProperty('step', 10).get('value') === true) { - return; - } else { - App.router.send('gotoStep10'); - } - }, - content: Em.Object.create({ cluster: null, hosts: null, @@ -691,10 +498,11 @@ App.InstallerController = Em.Controller.extend({ * Generate serviceComponents as pr the stack definition and save it to localdata * called form stepController step4WizardController */ - loadComponents: function (stepController) { + loadServiceComponents : function (stepController, displayOrderConfig, apiUrl) { var self = this; var method = 'GET'; - var url = (App.testMode) ? '/data/wizard/stack/hdp/version0.1.json' : App.apiPrefix + '/stacks/HDP/version/1.2.0'; // TODO: get this url from the stack selected by the user in Install Options page + var testUrl = '/data/wizard/stack/hdp/version/1.2.0.json'; + var url = (App.testMode) ? testUrl : App.apiPrefix + apiUrl; $.ajax({ type: method, url: url, @@ -703,14 +511,45 @@ App.InstallerController = Em.Controller.extend({ timeout: App.timeout, success: function (data) { var jsonData = jQuery.parseJSON(data); - console.log("TRACE: STep5 -> In success function for the getServiceComponents call"); - console.log("TRACE: STep5 -> value of the url is: " + url); - var serviceComponents = []; - jsonData.services.forEach(function (_service) { + console.log("TRACE: getService ajax call -> In success function for the getServiceComponents call"); + console.log("TRACE: jsonData.services : " + jsonData.services); + + // Creating Model + var Service = Ember.Object.extend({ + serviceName: null, + displayName: null, + isDisabled: true, + isSelected: true, + description:null, + version:null + }); + + var data = []; + + // loop through all the service components + for (var i = 0 ; i < displayOrderConfig.length ; i++) { + var entry = jsonData.services.filterProperty("name",displayOrderConfig[i].serviceName)[0]; - }, this); - stepController.set('components', jsonData.services); + // dont show the service whose isHidden is true + if ( displayOrderConfig[i].isHidden ) { + continue; + } + + var myService = Service.create({ + serviceName: entry.name, + displayName: displayOrderConfig[i].displayName, + isDisabled: i === 0 , + isSelected: true, + description: entry.comment, + version: entry.version + }); + + data.push(myService); + } + + stepController.set('serviceComponents', data); console.log('TRACE: service components: ' + JSON.stringify(stepController.get('components'))); + }, error: function (request, ajaxOptions, error) { diff --git a/ambari-web/app/controllers/main/charts/heatmap.js b/ambari-web/app/controllers/main/charts/heatmap.js index 039b521274..c10ee90781 100644 --- a/ambari-web/app/controllers/main/charts/heatmap.js +++ b/ambari-web/app/controllers/main/charts/heatmap.js @@ -32,7 +32,7 @@ App.MainChartsHeatmapController = Em.Controller.extend({ * @param event */ routeHostDetail: function(event){ - App.router.transitionTo('main.hostDetails.summary', event.context) + App.router.transitionTo('main.hosts.hostDetails.summary', event.context) }, showHeatMapMetric: function (event) { var metricItem = event.context; diff --git a/ambari-web/app/controllers/main/host/add_controller.js b/ambari-web/app/controllers/main/host/add_controller.js index d46e6d3b5f..edddd4522c 100644 --- a/ambari-web/app/controllers/main/host/add_controller.js +++ b/ambari-web/app/controllers/main/host/add_controller.js @@ -19,7 +19,7 @@ var App = require('app'); -App.AddHostController = Em.Controller.extend({ +App.AddHostController = App.WizardController.extend({ name: 'addHostController', @@ -52,115 +52,7 @@ App.AddHostController = Em.Controller.extend({ */ hideBackButton: true, - isStepDisabled: [], - - totalSteps: 9, - - init: function () { - this.isStepDisabled.pushObject(Ember.Object.create({ - step: 1, - value: false - })); - for (var i = 2; i <= this.totalSteps; i++) { - this.isStepDisabled.pushObject(Ember.Object.create({ - step: i, - value: true - })); - } - }, - - setStepsEnable: function () { - for (var i = 2; i <= this.totalSteps; i++) { - var step = this.get('isStepDisabled').findProperty('step', i); - if (i <= this.get('currentStep')) { - step.set('value', false); - } else { - step.set('value', true); - } - } - }.observes('currentStep'), - - /** - * Return current step of Add Host Wizard - */ - currentStep: function () { - return App.get('router').getWizardCurrentStep('addHost'); - }.property(), - - clusters: null, - - /** - * Set current step to new value. - * Method moved from App.router.setInstallerCurrentStep - * @param currentStep - * @param completed - */ - setCurrentStep: function (currentStep, completed) { - App.db.setWizardCurrentStep('addHost', currentStep, completed); - this.set('currentStep', currentStep); - }, - - isStep1: function () { - return this.get('currentStep') == 1; - }.property('currentStep'), - - isStep2: function () { - return this.get('currentStep') == 2; - }.property('currentStep'), - - isStep3: function () { - return this.get('currentStep') == 3; - }.property('currentStep'), - - isStep4: function () { - return this.get('currentStep') == 4; - }.property('currentStep'), - - isStep5: function () { - return this.get('currentStep') == 5; - }.property('currentStep'), - - isStep6: function () { - return this.get('currentStep') == 6; - }.property('currentStep'), - - isStep7: function () { - return this.get('currentStep') == 7; - }.property('currentStep'), - - gotoStep: function (step) { - if (this.get('isStepDisabled').findProperty('step', step).get('value') === false) { - App.router.send('gotoStep' + step); - } - }, - - gotoStep1: function () { - this.gotoStep(1); - }, - - gotoStep2: function () { - this.gotoStep(2); - }, - - gotoStep3: function () { - this.gotoStep(3); - }, - - gotoStep4: function () { - this.gotoStep(4); - }, - - gotoStep5: function () { - this.gotoStep(5); - }, - - gotoStep6: function () { - this.gotoStep(6); - }, - - gotoStep7: function () { - this.gotoStep(7); - }, + totalSteps: 7, /** * Load clusterInfo(step1) to model @@ -361,7 +253,7 @@ App.AddHostController = Em.Controller.extend({ loadServices: function () { var servicesInfo = App.db.getService(); if(!servicesInfo || !servicesInfo.length){ - servicesInfo = require('data/mock/services').slice(0); + servicesInfo = require('data/services').slice(0); servicesInfo.forEach(function (item) { item.isSelected = App.Service.find().someProperty('id', item.serviceName) item.isInstalled = item.isSelected; diff --git a/ambari-web/app/controllers/main/service/add_controller.js b/ambari-web/app/controllers/main/service/add_controller.js index 6f66d49512..f026e9c7d9 100644 --- a/ambari-web/app/controllers/main/service/add_controller.js +++ b/ambari-web/app/controllers/main/service/add_controller.js @@ -19,7 +19,7 @@ var App = require('app'); -App.AddServiceController = Em.Controller.extend({ +App.AddServiceController = App.WizardController.extend({ name: 'addServiceController', @@ -52,116 +52,7 @@ App.AddServiceController = Em.Controller.extend({ */ hideBackButton: true, - isStepDisabled: [], - - totalSteps: 9, - - init: function () { - this.isStepDisabled.pushObject(Ember.Object.create({ - step: 1, - value: false - })); - for (var i = 2; i <= this.totalSteps; i++) { - this.isStepDisabled.pushObject(Ember.Object.create({ - step: i, - value: true - })); - } - }, - - setStepsEnable: function () { - for (var i = 2; i <= this.totalSteps; i++) { - var step = this.get('isStepDisabled').findProperty('step', i); - if (i <= this.get('currentStep')) { - step.set('value', false); - } else { - step.set('value', true); - } - } - }.observes('currentStep'), - - /** - * Return current step of Add Host Wizard - */ - currentStep: function () { - return App.get('router').getWizardCurrentStep('addService'); - }.property(), - - clusters: null, - - /** - * Set current step to new value. - * Method moved from App.router.setInstallerCurrentStep - * @param currentStep - * @param completed - */ - setCurrentStep: function (currentStep, completed) { - App.db.setWizardCurrentStep('addService', currentStep, completed); - this.set('currentStep', currentStep); - }, - - isStep1: function () { - return this.get('currentStep') == 1; - }.property('currentStep'), - - isStep2: function () { - return this.get('currentStep') == 2; - }.property('currentStep'), - - isStep3: function () { - return this.get('currentStep') == 3; - }.property('currentStep'), - - isStep4: function () { - return this.get('currentStep') == 4; - }.property('currentStep'), - - isStep5: function () { - return this.get('currentStep') == 5; - }.property('currentStep'), - - isStep6: function () { - return this.get('currentStep') == 6; - }.property('currentStep'), - - isStep7: function () { - return this.get('currentStep') == 7; - }.property('currentStep'), - - gotoStep: function (step) { - if (this.get('isStepDisabled').findProperty('step', step).get('value') === false) { - App.router.send('gotoStep' + step); - } - }, - - gotoStep1: function () { - this.gotoStep(1); - }, - - gotoStep2: function () { - this.gotoStep(2); - }, - - gotoStep3: function () { - this.gotoStep(3); - }, - - gotoStep4: function () { - this.gotoStep(4); - }, - - gotoStep5: function () { - this.gotoStep(5); - }, - - gotoStep6: function () { - this.gotoStep(6); - }, - - gotoStep7: function () { - this.gotoStep(7); - }, - + totalSteps: 7, /** * Load clusterInfo(step1) to model @@ -275,7 +166,7 @@ App.AddServiceController = Em.Controller.extend({ loadServices: function () { var servicesInfo = App.db.getService(); if(!servicesInfo || !servicesInfo.length){ - servicesInfo = require('data/mock/services').slice(0); + servicesInfo = require('data/services').slice(0); servicesInfo.forEach(function(item, index){ servicesInfo[index].isSelected = App.Service.find().someProperty('id', item.serviceName); servicesInfo[index].isDisabled = servicesInfo[index].isSelected; diff --git a/ambari-web/app/controllers/wizard.js b/ambari-web/app/controllers/wizard.js new file mode 100644 index 0000000000..72ebdc6e81 --- /dev/null +++ b/ambari-web/app/controllers/wizard.js @@ -0,0 +1,199 @@ +/** + * 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.WizardController = Em.Controller.extend({ + + isStepDisabled: [], + + init: function () { + this.clusters = App.Cluster.find(); + this.isStepDisabled.pushObject(Ember.Object.create({ + step: 1, + value: false + })); + for (var i = 2; i <= this.totalSteps; i++) { + this.isStepDisabled.pushObject(Ember.Object.create({ + step: i, + value: true + })); + } + // window.onbeforeunload = function () { + // return "You have not saved your document yet. If you continue, your work will not be saved." + //} + }, + + setStepsEnable: function () { + for (var i = 2; i <= this.totalSteps; i++) { + var step = this.get('isStepDisabled').findProperty('step', i); + if (i <= this.get('currentStep')) { + step.set('value', false); + } else { + step.set('value', true); + } + } + }.observes('currentStep'), + + setLowerStepsDisable: function (stepNo) { + for (var i = 1; i < stepNo; i++) { + var step = this.get('isStepDisabled').findProperty('step', i); + step.set('value', true); + } + }, + + prevInstallStatus: function () { + console.log('Inside the prevInstallStep function: The name is ' + App.router.get('loginController.loginName')); + var result = App.db.isCompleted() + if (result == '1') { + return true; + } + }.property('App.router.loginController.loginName'), + + /** + * Set current step to new value. + * Method moved from App.router.setInstallerCurrentStep + * @param currentStep + * @param completed + */ + currentStep: function () { + return App.get('router').getWizardCurrentStep(this.get('name').substr(0, this.get('name').length - 10)); + }.property(), + + /** + * Set current step to new value. + * Method moved from App.router.setInstallerCurrentStep + * @param currentStep + * @param completed + */ + setCurrentStep: function (currentStep, completed) { + App.db.setWizardCurrentStep(this.get('name').substr(0, this.get('name').length - 10), currentStep, completed); + this.set('currentStep', currentStep); + }, + + clusters: null, + + isStep1: function () { + return this.get('currentStep') == 1; + }.property('currentStep'), + + isStep2: function () { + return this.get('currentStep') == 2; + }.property('currentStep'), + + isStep3: function () { + return this.get('currentStep') == 3; + }.property('currentStep'), + + isStep4: function () { + return this.get('currentStep') == 4; + }.property('currentStep'), + + isStep5: function () { + return this.get('currentStep') == 5; + }.property('currentStep'), + + isStep6: function () { + return this.get('currentStep') == 6; + }.property('currentStep'), + + isStep7: function () { + return this.get('currentStep') == 7; + }.property('currentStep'), + + isStep8: function () { + return this.get('currentStep') == 8; + }.property('currentStep'), + + isStep9: function () { + return this.get('currentStep') == 9; + }.property('currentStep'), + + isStep10: function () { + return this.get('currentStep') == 10; + }.property('currentStep'), + + gotoStep: function (step) { + if (this.get('isStepDisabled').findProperty('step', step).get('value') !== false) { + return; + } + if ((this.get('currentStep') - step) > 1) { + App.ModalPopup.show({ + header: Em.I18n.t('installer.navigation.warning.header'), + onPrimary: function () { + App.router.send('gotoStep' + step); + this.hide(); + }, + body: "If you proceed to go back to Step " + step + ", you will lose any changes you have made beyond this step" + }); + } else { + App.router.send('gotoStep' + step); + } + }, + + gotoStep1: function () { + this.gotoStep(1); + }, + + gotoStep2: function () { + this.gotoStep(2); + }, + + gotoStep3: function () { + this.gotoStep(3); + }, + + gotoStep4: function () { + this.gotoStep(4); + }, + + gotoStep5: function () { + this.gotoStep(5); + }, + + gotoStep6: function () { + this.gotoStep(6); + }, + + gotoStep7: function () { + this.gotoStep(7); + }, + + gotoStep8: function () { + this.gotoStep(8); + }, + + gotoStep9: function () { + this.gotoStep(9); + }, + + gotoStep10: function () { + this.gotoStep(10); + }, + + load: function (name, reload) { + if (this.get('content.' + name) && !reload) { + return false; + } + var result = App.db['get' + name.capitalize()]; + if (!result) result = this['get' + name.capitalize()]; + this.set('content.' + name, result); + console.log("Installer controller: loaded" + name, result); + } +}) diff --git a/ambari-web/app/controllers/wizard/step3_controller.js b/ambari-web/app/controllers/wizard/step3_controller.js index ae1a0386cd..6a5e1e13a8 100644 --- a/ambari-web/app/controllers/wizard/step3_controller.js +++ b/ambari-web/app/controllers/wizard/step3_controller.js @@ -23,7 +23,8 @@ App.WizardStep3Controller = Em.Controller.extend({ hosts: [], content: [], bootHosts: [], - registrationAttempt: 7, + maxRegistrationAttempts: 20, + registrationAttempts: null, isSubmitDisabled: true, categories: ['All Hosts', 'Success', 'Error'], category: 'All Hosts', @@ -49,13 +50,15 @@ App.WizardStep3Controller = Em.Controller.extend({ } } else { this.set('bootHosts', this.get('hosts')); - this.isHostsRegistered(this.getHostInfo); + this.isHostsRegistered(); } }, clearStep: function () { this.hosts.clear(); this.bootHosts.clear(); + this.set('isSubmitDisabled', true); + this.set('registrationAttempts', 1); }, loadStep: function () { @@ -113,7 +116,7 @@ App.WizardStep3Controller = Em.Controller.extend({ /* Returns the current set of visible hosts on view (All, Succeeded, Failed) */ visibleHosts: function () { if (this.get('category') === 'Success') { - return (this.hosts.filterProperty('bootStatus', 'DONE')); + return (this.hosts.filterProperty('bootStatus', 'REGISTERED')); } else if (this.get('category') === 'Error') { return (this.hosts.filterProperty('bootStatus', 'FAILED')); } else { // if (this.get('category') === 'All Hosts') @@ -166,7 +169,7 @@ App.WizardStep3Controller = Em.Controller.extend({ if (self.get('content.hosts.manualInstall') !== true) { self.doBootstrap(); } else { - self.isHostsRegistered(self.getHostInfo); + self.isHostsRegistered(); } this.hide(); }, @@ -241,10 +244,10 @@ App.WizardStep3Controller = Em.Controller.extend({ }, startRegistration: function () { - this.isHostsRegistered(this.getHostInfo); + this.isHostsRegistered(); }, - isHostsRegistered: function (callback) { + isHostsRegistered: function () { var self = this; var hosts = this.get('bootHosts'); var url = App.testMode ? '/data/wizard/bootstrap/single_host_registration.json' : App.apiPrefix + '/hosts'; @@ -254,6 +257,7 @@ App.WizardStep3Controller = Em.Controller.extend({ url: url, timeout: App.timeout, success: function (data) { + console.log('registration attempt #' + self.get('registrationAttempts')); var jsonData; if (App.testMode === true) { jsonData = data; @@ -264,31 +268,38 @@ App.WizardStep3Controller = Em.Controller.extend({ console.log("Error: jsonData is null"); return; } - if (jsonData.items.length === 0) { - if (self.get('registrationAttempt') !== 0) { - count--; - window.setTimeout(function () { - self.isHostsRegistered(callback); - }, 3000); - return; - } else { - self.registerErrPopup(Em.I18n.t('installer.step3.hostRegister.popup.header'), Em.I18n.t('installer.step3.hostRegister.popup.body')); - return; - } - } - var flag = true; + + // keep polling until all hosts are registered + var allRegistered = true; hosts.forEach(function (_host) { if (jsonData.items.someProperty('Hosts.host_name', _host.name)) { - _host.set('bootStatus', 'DONE'); - _host.set('bootLog', 'Success'); + if (_host.get('bootStatus') != 'REGISTERED') { + _host.set('bootStatus', 'REGISTERED'); + _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + '\nRegistration with the server succeeded.'); + } } else { - flag = false; + allRegistered = false; + if (_host.get('bootStatus') != 'FAILED' && _host.get('bootStatus') != 'REGISTERING') { + _host.set('bootStatus', 'REGISTERING'); + currentBootLog = _host.get('bootLog') != null ? _host.get('bootLog') : ''; + _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + '\nRegistering with the server...'); + } } }, this); - if (flag) { - callback.apply(self); + if (allRegistered) { + self.getHostInfo(); + } else if (self.get('maxRegistrationAttempts') - self.get('registrationAttempts') >= 0) { + self.set('registrationAttempts', self.get('registrationAttempts') + 1); + window.setTimeout(function () { + self.isHostsRegistered(); + }, 3000); } else { - self.registerErrPopup(Em.I18n.t('installer.step3.hostRegister.popup.header'), Em.I18n.t('installer.step3.hostRegister.popup.body')); + // maxed out on registration attempts. mark all REGISTERING hosts to FAILED + hosts.filterProperty('bootStatus', 'REGISTERING').forEach(function (_host) { + _host.set('bootStatus', 'FAILED'); + _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + '\nRegistration with the server failed.'); + }); + self.getHostInfo(); } }, error: function () { @@ -315,8 +326,6 @@ App.WizardStep3Controller = Em.Controller.extend({ /** * Get disk info and cpu count of booted hosts from server */ - - getHostInfo: function () { var self = this; var kbPerGb = 1024; @@ -336,16 +345,16 @@ App.WizardStep3Controller = Em.Controller.extend({ jsonData = jQuery.parseJSON(data); } hosts.forEach(function (_host) { - if (jsonData.items.someProperty('Hosts.host_name', _host.name)) { - var host = jsonData.items.findProperty('Hosts.host_name', _host.name); + var host = jsonData.items.findProperty('Hosts.host_name', _host.name); + if (host) { _host.cpu = host.Hosts.cpu_count; _host.memory = ((parseInt(host.Hosts.total_mem))).toFixed(2); console.log("The value of memory is: " + _host.memory); } - }, this); + }); self.set('bootHosts', hosts); console.log("The value of hosts: " + JSON.stringify(hosts)); - self.stopRegistrataion(); + self.stopRegistration(); }, error: function () { @@ -356,7 +365,7 @@ App.WizardStep3Controller = Em.Controller.extend({ }); }, - stopRegistrataion: function () { + stopRegistration: function () { this.set('isSubmitDisabled', false); }, diff --git a/ambari-web/app/controllers/wizard/step5_controller.js b/ambari-web/app/controllers/wizard/step5_controller.js index 3202fdf37f..834889a9f1 100644 --- a/ambari-web/app/controllers/wizard/step5_controller.js +++ b/ambari-web/app/controllers/wizard/step5_controller.js @@ -58,7 +58,7 @@ App.WizardStep5Controller = Em.Controller.extend({ for (var index in hostInfo) { var _host = hostInfo[index]; - if (_host.bootStatus === 'DONE') { // TODO: remove "true" after integrating with bootstrap + if (_host.bootStatus === 'REGISTERED') { var hostObj = Ember.Object.create({ host_name:_host.name, diff --git a/ambari-web/app/controllers/wizard/step6_controller.js b/ambari-web/app/controllers/wizard/step6_controller.js index 6d3957ba65..3cd79bd9fb 100644 --- a/ambari-web/app/controllers/wizard/step6_controller.js +++ b/ambari-web/app/controllers/wizard/step6_controller.js @@ -166,8 +166,9 @@ App.WizardStep6Controller = Em.Controller.extend({ var hostInfo = this.get('content.hostsInfo'); var hostNames = []; for (var index in hostInfo) { - if (hostInfo[index].bootStatus === 'DONE') //TODO: remove true after integration with bootstrap + if (hostInfo[index].bootStatus === 'REGISTERED') { hostNames.push(hostInfo[index].name); + } } return hostNames; }, diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js index 128c592ba1..5ef927b203 100644 --- a/ambari-web/app/controllers/wizard/step8_controller.js +++ b/ambari-web/app/controllers/wizard/step8_controller.js @@ -28,6 +28,8 @@ App.WizardStep8Controller = Em.Controller.extend({ globals: [], configMapping: require('data/config_mapping'), + isSubmitDisabled : false, + selectedServices: function () { return this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false); }.property('content.services').cacheable(), @@ -596,6 +598,12 @@ App.WizardStep8Controller = Em.Controller.extend({ */ submit: function () { + if (this.get('isSubmitDisabled')) { + return; + } + + this.set('isSubmitDisabled', true); + if (App.testMode) { App.router.send('next'); return; diff --git a/ambari-web/app/controllers/wizard/step9_controller.js b/ambari-web/app/controllers/wizard/step9_controller.js index cc062c2b98..84a19bcf3f 100644 --- a/ambari-web/app/controllers/wizard/step9_controller.js +++ b/ambari-web/app/controllers/wizard/step9_controller.js @@ -95,7 +95,7 @@ App.WizardStep9Controller = Em.Controller.extend({ console.log("TRACE: host name is: " + hostInfo[index].name); } // return hosts; - return hosts.filterProperty('bootStatus', 'DONE'); //TODO: uncomment after actual hookup with bootstrap + return hosts.filterProperty('bootStatus', 'REGISTERED'); }, renderHosts: function (hostsInfo) { diff --git a/ambari-web/app/data/mock/services.js b/ambari-web/app/data/services.js index 70cb548a21..70cb548a21 100644 --- a/ambari-web/app/data/mock/services.js +++ b/ambari-web/app/data/services.js diff --git a/ambari-web/app/initialize.js b/ambari-web/app/initialize.js index 312f147449..d4eca24fff 100644 --- a/ambari-web/app/initialize.js +++ b/ambari-web/app/initialize.js @@ -30,6 +30,7 @@ App.componentsUpdateInterval = 6000; App.contentUpdateInterval = 15000; require('messages'); +require('utils/base64'); require('utils/data_table'); require('utils/db'); require('utils/helper'); diff --git a/ambari-web/app/mappers/alerts_mapper.js b/ambari-web/app/mappers/alerts_mapper.js index fa64bd1d39..c1d867c99a 100644 --- a/ambari-web/app/mappers/alerts_mapper.js +++ b/ambari-web/app/mappers/alerts_mapper.js @@ -42,11 +42,26 @@ App.alertsMapper = App.QuickDataMapper.create({ return; } if (json.alerts) { - var result = []; - json.alerts.forEach(function (item) { - result.push(this.parseIt(item, this.config)); - }, this); - App.store.loadMany(this.get('model'), result); + if (App.Alert.find().content.length > 0) { + this.update(json); + } else { + var result = []; + json.alerts.forEach(function (item) { + result.push(this.parseIt(item, this.config)); + }, this); + App.store.loadMany(this.get('model'), result); + } } + }, + update: function(json){ + var alerts = App.Alert.find(); + var result = []; + json.alerts.forEach(function (item) { + if (!alerts.filterProperty('title', item.service_description).length) { + result.push(this.parseIt(item, this.config)); + } + }, this); + App.store.loadMany(this.get('model'), result); + } }); diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 1fc58c7a7b..6cb6f30c96 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -40,6 +40,7 @@ Em.I18n.translations = { 'topnav.help.href':'http://incubator.apache.org/ambari/install.html', 'installer.header':'Cluster Install Wizard', + 'installer.navigation.warning.header':'Navigation Warning', 'installer.step1.header':'Welcome', 'installer.step1.body.header':'Welcome to Apache Ambari!', 'installer.step1.body':'Ambari makes it easy to install, manage, and monitor Hadoop clusters.<br>' + @@ -93,8 +94,6 @@ Em.I18n.translations = { 'installer.step3.hosts.remove.popup.body':'Are you sure you want to remove the selected host(s)?', 'installer.step3.hosts.retry.popup.header':'Retry Host Discovery', 'installer.step3.hosts.retry.popup.body':'Are you sure you want to retry discovery of the selected host(s)?', - 'installer.step3.hostRegister.popup.header':'Error in Host Registration', - 'installer.step3.hostRegister.popup.body':'All/Some hosts bootstrapped but unable to register with server', 'installer.step3.hostInformation.popup.header':'Error in retrieving host Information', 'installer.step3.hostInformation.popup.body' : 'All bootstrapped hosts registered but unable to retrieve cpu and memory related information', 'installer.step4.header':'Choose Services', diff --git a/ambari-web/app/models/hosts.js b/ambari-web/app/models/hosts.js index 55dfae6702..da2a3428d6 100644 --- a/ambari-web/app/models/hosts.js +++ b/ambari-web/app/models/hosts.js @@ -31,33 +31,55 @@ App.HostInfo = Ember.Object.extend({ bootStatusForDisplay:function () { switch (this.get('bootStatus')) { - case 'DONE': + case 'REGISTERED': return 'Success'; case 'FAILED': return 'Failed'; case 'RUNNING': - return 'Running'; + return 'Installing'; + case 'DONE': + case 'REGISTERING': + default: + return 'Registering'; } }.property('bootStatus'), bootBarColor:function () { switch (this.get('bootStatus')) { - case 'DONE': + case 'REGISTERED': return 'progress-success'; case 'FAILED': return 'progress-danger'; case 'RUNNING': + case 'DONE': + case 'REGISTERING': default: return 'progress-info'; } }.property('bootStatus'), - isBootDone:function () { + bootStatusColor:function () { switch (this.get('bootStatus')) { + case 'REGISTERED': + return 'text-success'; + case 'FAILED': + return 'text-error'; + case 'RUNNING': case 'DONE': + case 'REGISTERING': + default: + return 'text-info'; + } + }.property('bootStatus'), + + isBootDone:function () { + switch (this.get('bootStatus')) { + case 'REGISTERED': case 'FAILED': return true; case 'RUNNING': + case 'DONE': + case 'REGISTERING': default: return false; } diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js index d50ad68036..b3667c9228 100644 --- a/ambari-web/app/router.js +++ b/ambari-web/app/router.js @@ -131,7 +131,8 @@ App.Router = Em.Router.extend({ login: function (postLogin) { var controller = this.get('loginController'); - var loginName = controller.get('loginName'); + var loginName = controller.get('loginName').toLowerCase(); + controller.set('loginName', loginName); var hash = window.btoa(loginName + ":" + controller.get('password')); var router = this; $.ajax({ diff --git a/ambari-web/app/routes/add_host_routes.js b/ambari-web/app/routes/add_host_routes.js index 459ede8731..7c49a8e354 100644 --- a/ambari-web/app/routes/add_host_routes.js +++ b/ambari-web/app/routes/add_host_routes.js @@ -174,6 +174,9 @@ module.exports = Em.Route.extend({ controller.setCurrentStep('6', false); controller.dataLoading().done(function () { controller.loadAllPriorSteps(); + if (!App.testMode) { //if test mode is ON don't disable prior steps link. + controller.setLowerStepsDisable(6); + } controller.connectOutlet('wizardStep9', controller.get('content')); }) }, @@ -191,6 +194,9 @@ module.exports = Em.Route.extend({ wizardStep9Controller.navigateStep(); } }, + unroutePath: function() { + return false; + }, next: function (router) { var addHostController = router.get('addHostController'); var wizardStep9Controller = router.get('wizardStep9Controller'); diff --git a/ambari-web/app/routes/add_service_routes.js b/ambari-web/app/routes/add_service_routes.js index c47d56d42f..bec1cdc81a 100644 --- a/ambari-web/app/routes/add_service_routes.js +++ b/ambari-web/app/routes/add_service_routes.js @@ -175,6 +175,9 @@ module.exports = Em.Route.extend({ controller.setCurrentStep('6', false); controller.dataLoading().done(function () { controller.loadAllPriorSteps(); + if (!App.testMode) { //if test mode is ON don't disable prior steps link. + controller.setLowerStepsDisable(6); + } controller.connectOutlet('wizardStep9', controller.get('content')); }) }, @@ -192,6 +195,9 @@ module.exports = Em.Route.extend({ wizardStep9Controller.navigateStep(); } }, + unroutePath: function() { + return false; + }, next: function (router) { var addServiceController = router.get('addServiceController'); var wizardStep9Controller = router.get('wizardStep9Controller'); diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js index 63a20a06cd..548d9bc1d7 100644 --- a/ambari-web/app/routes/installer.js +++ b/ambari-web/app/routes/installer.js @@ -135,8 +135,13 @@ module.exports = Em.Route.extend({ var wizardStep3Controller = router.get('wizardStep3Controller'); installerController.saveConfirmedHosts(wizardStep3Controller); + App.db.setBootStatus(true); - App.db.setService(require('data/mock/services')); + var displayOrderConfig = require('data/services'); + var apiUrl = '/stacks/HDP/version/1.2.0'; + router.get('installerController').loadServiceComponents(router.get('wizardStep4Controller'), displayOrderConfig, apiUrl); + var apiService = router.get('wizardStep4Controller').get('serviceComponents'); + App.db.setService(apiService); router.transitionTo('step4'); }, /** @@ -284,6 +289,9 @@ module.exports = Em.Route.extend({ wizardStep9Controller.navigateStep(); } }, + unroutePath: function() { + return false; + }, next: function (router) { var installerController = router.get('installerController'); var wizardStep9Controller = router.get('wizardStep9Controller'); diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js index 6622ba4219..a7bbcc4f89 100644 --- a/ambari-web/app/routes/main.js +++ b/ambari-web/app/routes/main.js @@ -259,7 +259,7 @@ module.exports = Em.Route.extend({ }, showDetails:function (router, event) { router.get('mainHostDetailsController').setBack(true); - router.transitionTo('hostDetails.index', event.context) + router.transitionTo('hosts.hostDetails.index', event.context) }, filterHosts:function (router, component) { router.transitionTo('hosts'); @@ -335,7 +335,7 @@ module.exports = Em.Route.extend({ }, showDetails:function (router, event) { router.get('mainHostDetailsController').setBack(true); - router.transitionTo('hostDetails.index', event.context) + router.transitionTo('hosts.hostDetails.index', event.context) } }), showService:Em.Router.transitionTo('service'), @@ -347,10 +347,10 @@ module.exports = Em.Route.extend({ selectService:Em.Route.transitionTo('services.service'), selectHost:function (router, event) { router.get('mainHostDetailsController').setBack(false); - router.transitionTo('hostDetails.index', event.context); + router.transitionTo('hosts.hostDetails.index', event.context); }, filterHosts:function (router, component) { router.get('mainHostController').filterByComponent(component.context); - router.transitionTo('hosts'); + router.transitionTo('hosts.index'); } });
\ No newline at end of file diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 83bde02491..2951b351c4 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -674,6 +674,12 @@ a:focus { /*start chart/style graphs*/ .chart-container { + cursor: pointer; + cursor:-moz-zoom-in; + cursor:-webkit-zoom-in; + &.chart-container-popup { + cursor: auto; + } position: relative; margin: 20px 15px 0px 15px; @@ -707,6 +713,14 @@ a:focus { .rickshaw_legend { background-color: #999999 !important; } + .rickshaw_graph { + .x_tick{ + .title { + bottom: -6px; + opacity: 0.75; + } + } + } .chart-overlay { position: absolute; top: 0; @@ -774,6 +788,9 @@ a:focus { .add-service-button { margin: 20px 20px 10px; } + .operations-count{ + background: #953B39; + } } .nav-pills.move { @@ -1535,6 +1552,11 @@ ul.filter { color: #777777; margin-top: 5px; } + .heatmap-host { + display: block; + width: 100%; + height: 100%; + } } /*End Heatmap*/ diff --git a/ambari-web/app/styles/apps.less b/ambari-web/app/styles/apps.less index 18f3fa90f3..1d7c685080 100644 --- a/ambari-web/app/styles/apps.less +++ b/ambari-web/app/styles/apps.less @@ -1,10 +1,28 @@ #apps{ + select, + input[type="text"], + input[type="datetime"], + input[type="datetime-local"], + input[type="date"], + input[type="month"], + input[type="time"], + input[type="week"], + input[type="number"], + input[type="email"], + input[type="url"], + input[type="search"], + input[type="tel"], + input[type="color"] { + margin-bottom: 0px; + } + td .red { color: red; } .table thead th{ vertical-align:top; + padding-bottom: 0px; } .avg-table { table-layout: fixed; diff --git a/ambari-web/app/templates/main/charts/heatmap.hbs b/ambari-web/app/templates/main/charts/heatmap.hbs index 893ced3f0b..6e08350efd 100644 --- a/ambari-web/app/templates/main/charts/heatmap.hbs +++ b/ambari-web/app/templates/main/charts/heatmap.hbs @@ -29,7 +29,7 @@ <ul class="dropdown-menu"> {{#each category in controller.allMetrics}} <li class="dropdown-submenu"> - <a tabindex="-1" href="#">{{category.label}}</a> + <a tabindex="-1" >{{category.label}}</a> <ul class="dropdown-menu"> {{#each metric in category.items}} <li> diff --git a/ambari-web/app/templates/main/charts/heatmap/heatmap_host.hbs b/ambari-web/app/templates/main/charts/heatmap/heatmap_host.hbs index 5c83e3276b..07241d0b1b 100644 --- a/ambari-web/app/templates/main/charts/heatmap/heatmap_host.hbs +++ b/ambari-web/app/templates/main/charts/heatmap/heatmap_host.hbs @@ -16,4 +16,6 @@ * limitations under the License. }} -<div {{bindAttr class="view.content.healthStatus view.hostClass"}} {{bindAttr style="view.hostTemperatureStyle"}}></div>
\ No newline at end of file +<div {{bindAttr class="view.content.healthStatus view.hostClass"}} {{bindAttr style="view.hostTemperatureStyle"}}> + <a href="#" class="heatmap-host" {{action "routeHostDetail" view.content target="controller"}}></a> +</div>
\ No newline at end of file diff --git a/ambari-web/app/templates/main/charts/heatmap/heatmap_rack.hbs b/ambari-web/app/templates/main/charts/heatmap/heatmap_rack.hbs index a87191c73f..0bb176b975 100644 --- a/ambari-web/app/templates/main/charts/heatmap/heatmap_rack.hbs +++ b/ambari-web/app/templates/main/charts/heatmap/heatmap_rack.hbs @@ -44,11 +44,8 @@ <!--</div>--> <div {{bindAttr class="view.heatmapTogglerClass view.hostsBlockClass"}}> {{#each rack.hosts}} - <a href="#" {{action "routeHostDetail" this target="controller"}}> <div {{bindAttr style="view.hostCssStyle"}}> {{view App.MainChartsHeatmapHostView contentBinding="this"}} </div> - </a> {{/each}} - </div>
\ No newline at end of file diff --git a/ambari-web/app/templates/main/charts/linear_time.hbs b/ambari-web/app/templates/main/charts/linear_time.hbs index 115c408769..f89e26decc 100644 --- a/ambari-web/app/templates/main/charts/linear_time.hbs +++ b/ambari-web/app/templates/main/charts/linear_time.hbs @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. }} -<div id="{{unbound view.id}}-container" class="chart-container" {{action showGraphInPopup target="view"}}> +<div id="{{unbound view.id}}-container" class="chart-container" {{action showGraphInPopup target="view"}} title="Click to zoom"> <div id="{{unbound view.id}}-yaxis" class="chart-y-axis"></div> <div id="{{unbound view.id}}-xaxis" class="chart-x-axis"></div> <div id="{{unbound view.id}}-legend" class="chart-legend"></div> diff --git a/ambari-web/app/templates/main/dashboard.hbs b/ambari-web/app/templates/main/dashboard.hbs index b30bea2576..56e9f17bc2 100644 --- a/ambari-web/app/templates/main/dashboard.hbs +++ b/ambari-web/app/templates/main/dashboard.hbs @@ -26,7 +26,7 @@ </div> <dl class="dl-horizontal services"> {{#each item in view.content}} - {{view item.viewName serviceBinding="item.model"}} + {{view item.viewName serviceBinding="item.model"}} {{/each}} </dl> </div> diff --git a/ambari-web/app/templates/main/dashboard/service/hbase.hbs b/ambari-web/app/templates/main/dashboard/service/hbase.hbs index 2084524522..bf54fe765d 100644 --- a/ambari-web/app/templates/main/dashboard/service/hbase.hbs +++ b/ambari-web/app/templates/main/dashboard/service/hbase.hbs @@ -19,6 +19,11 @@ {{#unless view.showOnlyRows}} <div class="clearfix" {{action toggleInfoView target="view"}}> <div class="name span2"> + {{#if view.isCollapsed}} + <i class="icon-arrow-down pull-left"></i> + {{else}} + <i class="icon-arrow-right pull-left"></i> + {{/if}} {{view App.MainDashboardServiceHealthView serviceBinding="view.service"}} <a {{action selectService view.service href=true}}>{{view.service.displayName}}</a> {{#if view.criticalAlertsCount}} diff --git a/ambari-web/app/templates/main/dashboard/service/hdfs.hbs b/ambari-web/app/templates/main/dashboard/service/hdfs.hbs index b2274b8c94..6ccd95250b 100644 --- a/ambari-web/app/templates/main/dashboard/service/hdfs.hbs +++ b/ambari-web/app/templates/main/dashboard/service/hdfs.hbs @@ -19,6 +19,11 @@ {{#unless view.showOnlyRows}} <div class="clearfix" {{action toggleInfoView target="view"}}> <div class="name span2"> + {{#if view.isCollapsed}} + <i class="icon-arrow-down pull-left"></i> + {{else}} + <i class="icon-arrow-right pull-left"></i> + {{/if}} {{view App.MainDashboardServiceHealthView serviceBinding="view.service"}} <a {{action selectService view.service href=true}}>{{view.service.displayName}}</a> {{#if view.criticalAlertsCount}} diff --git a/ambari-web/app/templates/main/dashboard/service/mapreduce.hbs b/ambari-web/app/templates/main/dashboard/service/mapreduce.hbs index ab3ee424e6..1ac15a9da5 100644 --- a/ambari-web/app/templates/main/dashboard/service/mapreduce.hbs +++ b/ambari-web/app/templates/main/dashboard/service/mapreduce.hbs @@ -19,6 +19,11 @@ {{#unless view.showOnlyRows}} <div class="clearfix" {{action toggleInfoView target="view"}}> <div class="name span2"> + {{#if view.isCollapsed}} + <i class="icon-arrow-down pull-left"></i> + {{else}} + <i class="icon-arrow-right pull-left"></i> + {{/if}} {{view App.MainDashboardServiceHealthView serviceBinding="view.service"}} <a {{action selectService view.service href=true}}>{{view.service.displayName}}</a> {{#if view.criticalAlertsCount}} diff --git a/ambari-web/app/templates/main/host.hbs b/ambari-web/app/templates/main/host.hbs index 50e08749a6..524f3e15c3 100644 --- a/ambari-web/app/templates/main/host.hbs +++ b/ambari-web/app/templates/main/host.hbs @@ -31,7 +31,7 @@ <thead> <tr> <th>Name</th> - <th>Rack</th> + <th>Ip</th> <th>CPU</th> <th>RAM</th> <th>Disk Usage</th> @@ -39,7 +39,7 @@ <th>Components</th> </tr> <th class="notActive"><div class="view-wrapper">{{view view.nameFilterView viewName="nameFilterViewInstance"}}</div> <a href="#" {{action "clearFilterButtonClick" target="view"}} id="view_nameFilterViewInstance" class="ui-icon ui-icon-circle-close ui-name"></a></th> - <th class="notActive"><div class="view-wrapper">{{view view.rackFilterView viewName="rackFilterViewInstance"}}</div> <a href="#" {{action "clearFilterButtonClick" target="view"}} id="view_rackFilterViewInstance" class="ui-icon ui-icon-circle-close ui-rack"></a></th> + <th class="notActive"><div class="view-wrapper">{{view view.rackFilterView viewName="ipFilterViewInstance"}}</div> <a href="#" {{action "clearFilterButtonClick" target="view"}} id="view_ipFilterViewInstance" class="ui-icon ui-icon-circle-close ui-rack"></a></th> <th class="notActive"><div class="view-wrapper">{{view view.cpuFilterView viewName="cpuFilterViewInstance"}}</div> <a href="#" {{action "clearFilterButtonClick" target="view"}} id="view_cpuFilterViewInstance" class="ui-icon ui-icon-circle-close ui-cpu"></a></th> <th class="notActive"><div class="view-wrapper">{{view view.ramFilterView viewName="ramFilterViewInstance"}}</div> <a href="#" {{action "clearFilterButtonClick" target="view"}} id="view_ramFilterViewInstance" class="ui-icon ui-icon-circle-close ui-ram"></a></th> <th></th> @@ -57,7 +57,7 @@ <span {{bindAttr class="host.healthClass"}}></span> <a href="#" {{action "showDetails" host}}>{{unbound host.publicHostName}}</a> </td> - <td>{{host.rack}}</td> + <td>{{host.ip}}</td> <td>{{host.cpu}}</td> <td>{{host.memoryFormatted}}</td> <td> diff --git a/ambari-web/app/templates/main/service/info/client_summary.hbs b/ambari-web/app/templates/main/service/info/client_summary.hbs index f2721315df..b705281355 100644 --- a/ambari-web/app/templates/main/service/info/client_summary.hbs +++ b/ambari-web/app/templates/main/service/info/client_summary.hbs @@ -59,53 +59,4 @@ </div> </div> </div> - <div class="span6"> - <div class="box"> - <div class="box-header"> - <h4>Alerts</h4> - - <div class="btn-group"> - <a class="btn" target="_blank" rel="tooltip" title="Go to Nagios" {{bindAttr href="controller.nagiosUrl"}}><i - class="icon-link"></i></a> - </div> - </div> - <ul id='summary-alerts-list' class="alerts"> - {{#if controller.alerts.length}} - {{#each controller.alerts}} - <li class="status-{{unbound status}}"> - <div class="container-fluid"> - <div class="row-fluid"> - <div class="span1 status-icon"> - {{#if isOk}} - <i class="icon-ok icon-large"></i> - {{else}} - <i class="icon-remove icon-large"></i> - {{/if}} - </div> - <div class="span11"> - <div class="row-fluid"> - <div class="span7 title">{{title}} - </div> - <div rel="tooltip" {{bindAttr data-title="timeSinceAlertDetails"}} data-placement="right" class="span5 date-time">{{timeSinceAlert}}</div> - </div> - <div class="row-fluid message">{{message}}</div> - </div> - </div> - </div> - </li> - {{/each}} - {{else}} - {{#if controller.isNagiosInstalled}} - <div class="alert alert-info"> - No alerts - </div> - {{else}} - <div class="alert"> - Nagios service required for viewing alerts - </div> - {{/if}} - {{/if}} - </ul> - </div> - </div> </div> diff --git a/ambari-web/app/templates/main/service/info/summary.hbs b/ambari-web/app/templates/main/service/info/summary.hbs index 721ab9e798..b6a12865f8 100644 --- a/ambari-web/app/templates/main/service/info/summary.hbs +++ b/ambari-web/app/templates/main/service/info/summary.hbs @@ -47,16 +47,22 @@ {{#unless view.serviceStatus.mapreduce}} {{#unless view.serviceStatus.hbase}} {{#each component in controller.content.components}} - <tr> - {{#if component.isMaster}} - <td class="summary-label">{{component.displayName}}</td> - <td><a {{action selectHost component.host}} href="javascript:void(null)">{{component.host.publicHostName}}</a></td> - {{else}} - <td class="summary-label">{{component.displayName}}s</td> - <td><a {{action filterHosts component}} href="javascript:void(null)">{{component.displayName}}s</a></td> - {{/if}} - </tr> + <tr> + {{#if component.isMaster}} + <td class="summary-label">{{component.displayName}}</td> + <td><a {{action selectHost component.host}} href="javascript:void(null)">{{component.host.publicHostName}}</a></td> + {{else}} + <td class="summary-label">{{component.displayName}}s</td> + <td><a {{action filterHosts component}} href="javascript:void(null)">{{component.displayName}}s</a></td> + {{/if}} + </tr> {{/each}} + {{#if view.serviceStatus.ganglia}} + <tr> + <td class="summary-label">Ganglia Web UI</td> + <td><a target=_blank href="http://{{unbound view.gangliaServer}}/ganglia">{{view.gangliaServer}}/ganglia</a></td> + </tr> + {{/if}} {{/unless}} {{/unless}} {{/unless}} diff --git a/ambari-web/app/templates/wizard/step3.hbs b/ambari-web/app/templates/wizard/step3.hbs index 3a4af157c4..471f99d953 100644 --- a/ambari-web/app/templates/wizard/step3.hbs +++ b/ambari-web/app/templates/wizard/step3.hbs @@ -90,7 +90,7 @@ </td> <td> <a href="javascript:void(null)" - data-toggle="modal" {{action hostLogPopup host target="controller"}}>{{host.bootStatusForDisplay}}</a> + data-toggle="modal" {{action hostLogPopup host target="controller"}}><span {{bindAttr class="host.bootStatusColor"}}>{{host.bootStatusForDisplay}}</span></a> </td> <td> {{#if view.isRemovable}}<a class="btn btn-mini" {{action remove target="view"}}><i class="icon-trash"></i> diff --git a/ambari-web/app/templates/wizard/step4.hbs b/ambari-web/app/templates/wizard/step4.hbs index bdf5e3fb71..0cfac9638d 100644 --- a/ambari-web/app/templates/wizard/step4.hbs +++ b/ambari-web/app/templates/wizard/step4.hbs @@ -33,6 +33,7 @@ href="#" {{action selectMinimum target="controller"}} {{bindAttr class="isMinimum:selected:deselected"}}>minimum</a> </span> </th> + <th>Version</th> <th>Description</th> </tr> </thead> @@ -43,6 +44,7 @@ <td><label class="checkbox">{{view Ember.Checkbox disabledBinding="isDisabled" checkedBinding="isSelected"}}{{displayName}}</label> </td> + <td>{{version}}</td> <td>{{description}}</td> </tr> {{/unless}} diff --git a/ambari-web/app/templates/wizard/step8.hbs b/ambari-web/app/templates/wizard/step8.hbs index 67826adbec..74bef46415 100644 --- a/ambari-web/app/templates/wizard/step8.hbs +++ b/ambari-web/app/templates/wizard/step8.hbs @@ -46,5 +46,5 @@ </div> <div class="btn-area"> <a class="btn pull-left" {{action back href="true"}}>← Back</a> - <a class="btn btn-success pull-right" {{action submit target="controller"}}>Deploy →</a> + <a class="btn btn-success pull-right" id="spinner" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}}>Deploy →</a> </div> diff --git a/ambari-web/app/utils/graph.js b/ambari-web/app/utils/graph.js index 64f9b46a86..438b1e89a7 100644 --- a/ambari-web/app/utils/graph.js +++ b/ambari-web/app/utils/graph.js @@ -182,9 +182,18 @@ module.exports = { return y / 1000 + 's' }, formatter:function (series, x, y, formattedX, formattedY, d) { + var bytesFormatter = function(y) { + if (y >= 1125899906842624) { return Math.floor(10 * y / 1125899906842624)/10 + " PB" } + else if (y >= 1099511627776){ return Math.floor(10 * y / 1099511627776)/10 + " TB" } + else if (y >= 1073741824) { return Math.floor(10 * y / 1073741824)/10 + " GB" } + else if (y >= 1048576) { return Math.floor(10 * y / 1048576)/10 + " MB" } + else if (y >= 1024) { return Math.floor(10 * y / 1024)/10 + " KB" } + else { return y + " B"} + }; var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>'; return swatch + (d.label? d.label: d.name) + - '<br>Run-time: ' + formattedY + '<br>Wait-time: ' + formattedX; + '<br>Run-time: ' + formattedY + '<br>Wait-time: ' + formattedX + + '<br>I/O: ' + bytesFormatter(d.IO) + '<br>Status: ' + d.status; } }); diff --git a/ambari-web/app/views/common/chart/linear_time.js b/ambari-web/app/views/common/chart/linear_time.js index 317664e597..0c61f2d97f 100644 --- a/ambari-web/app/views/common/chart/linear_time.js +++ b/ambari-web/app/views/common/chart/linear_time.js @@ -84,6 +84,8 @@ App.ChartLinearTimeView = Ember.View.extend({ _popupGraph: null, + _seriesProperties: null, + popupSuffix: '-popup', isPopup: false, @@ -314,7 +316,8 @@ App.ChartLinearTimeView = Ember.View.extend({ var palette = new Rickshaw.Color.Palette({ scheme: this._paletteScheme }); - seriesData.forEach(function (series) { + var self = this; + seriesData.forEach(function (series, index) { series.color = /*this.colorForSeries(series) ||*/ palette.color(); series.stroke = 'rgba(0,0,0,0.3)'; if (isPopup) { @@ -424,12 +427,32 @@ App.ChartLinearTimeView = Ember.View.extend({ } if (isPopup) { + var self = this; + // In popup save selected metrics and show only them after data update + _graph.series.forEach(function(series, index) { + if (self.get('_seriesProperties') !== null && self.get('_seriesProperties')[index] !== null) { + if(self.get('_seriesProperties')[self.get('_seriesProperties').length - index - 1].length > 1) { + $('#'+self.get('id')+'-container'+self.get('popupSuffix')+' a.action:eq('+(self.get('_seriesProperties').length - index - 1)+')').parent('li').addClass('disabled'); + series.disable(); + } + } + }); + _graph.update(); + + $('#'+self.get('id')+'-container'+self.get('popupSuffix')+' a.action').click(function() { + var series = new Array(); + $('#'+self.get('id')+'-container'+self.get('popupSuffix')+' a.action').each(function(index, v) { + series[index] = v.parentNode.classList; + }); + self.set('_seriesProperties', series); + }); + + this.set('_popupGraph', _graph); } else { this.set('_graph', _graph); } - this.set('isPopup', false); }, @@ -450,7 +473,7 @@ App.ChartLinearTimeView = Ember.View.extend({ '<div class="modal-body">', '{{#if bodyClass}}{{view bodyClass}}', '{{else}}'+ - '<div id="'+this.get('id')+'-container'+this.get('popupSuffix')+'" class="chart-container">'+ + '<div id="'+this.get('id')+'-container'+this.get('popupSuffix')+'" class="chart-container chart-container'+this.get('popupSuffix')+'">'+ '<div id="'+this.get('id')+'-yaxis'+this.get('popupSuffix')+'" class="'+this.get('id')+'-yaxis chart-y-axis"></div>'+ '<div id="'+this.get('id')+'-xaxis'+this.get('popupSuffix')+'" class="'+this.get('id')+'-xaxis chart-x-axis"></div>'+ '<div id="'+this.get('id')+'-legend'+this.get('popupSuffix')+'" class="'+this.get('id')+'-legend chart-legend"></div>'+ diff --git a/ambari-web/app/views/main/admin/user/create.js b/ambari-web/app/views/main/admin/user/create.js index 12ec4230ae..4b98aebada 100644 --- a/ambari-web/app/views/main/admin/user/create.js +++ b/ambari-web/app/views/main/admin/user/create.js @@ -25,6 +25,7 @@ App.MainAdminUserCreateView = Em.View.extend({ var parent_controller=this.get("controller").controllers.mainAdminUserController; var form = this.get("userForm"); if(form.isValid()) { + form.getField("userName").set('value', form.getValues().userName.toLowerCase()); if(form.getValues().admin === "" || form.getValues().admin == true) { form.getField("roles").set("value","admin,user"); form.getField("admin").set("value","true"); diff --git a/ambari-web/app/views/main/dashboard.js b/ambari-web/app/views/main/dashboard.js index 45055ea958..04274e5b36 100644 --- a/ambari-web/app/views/main/dashboard.js +++ b/ambari-web/app/views/main/dashboard.js @@ -78,7 +78,7 @@ App.MainDashboardView = Em.View.extend({ } this.get('content').pushObject(Em.Object.create({ viewName: vName, - model: item2 + model: item2 || item })) }, this); }, diff --git a/ambari-web/app/views/main/dashboard/service.js b/ambari-web/app/views/main/dashboard/service.js index 2c28c91170..99515e7925 100644 --- a/ambari-web/app/views/main/dashboard/service.js +++ b/ambari-web/app/views/main/dashboard/service.js @@ -88,7 +88,7 @@ App.MainDashboardServiceView = Em.View.extend({ criticalAlertsCount: function () { var alerts = App.router.get('clusterController.alerts'); - return alerts.filterProperty('serviceType', this.get('service.id')).filterProperty('status', '1').length; - }.property('service.alerts') + return alerts.filterProperty('serviceType', this.get('service.id')).filterProperty('isOk', false).length; + }.property('App.router.clusterController.alerts') });
\ No newline at end of file diff --git a/ambari-web/app/views/main/dashboard/service/hbase.js b/ambari-web/app/views/main/dashboard/service/hbase.js index b4a313702a..7083e76acd 100644 --- a/ambari-web/app/views/main/dashboard/service/hbase.js +++ b/ambari-web/app/views/main/dashboard/service/hbase.js @@ -58,7 +58,10 @@ App.MainDashboardServiceHbaseView = App.MainDashboardServiceView.extend({ return App.Component.find().findProperty('componentName', 'HBASE_REGIONSERVER'); }.property('components'), + isCollapsed: false, + toggleInfoView: function() { $('#hbase-info').toggle('blind', 200); + this.set('isCollapsed', !this.isCollapsed); } });
\ No newline at end of file diff --git a/ambari-web/app/views/main/dashboard/service/hdfs.js b/ambari-web/app/views/main/dashboard/service/hdfs.js index a9a2d053a6..b0f0fa277b 100644 --- a/ambari-web/app/views/main/dashboard/service/hdfs.js +++ b/ambari-web/app/views/main/dashboard/service/hdfs.js @@ -79,7 +79,10 @@ App.MainDashboardServiceHdfsView = App.MainDashboardServiceView.extend({ return App.Component.find().findProperty('componentName', 'DATANODE'); }.property('+'), + isCollapsed: false, + toggleInfoView: function() { $('#hdfs-info').toggle('blind', 200); + this.set('isCollapsed', !this.isCollapsed); } });
\ No newline at end of file diff --git a/ambari-web/app/views/main/dashboard/service/mapreduce.js b/ambari-web/app/views/main/dashboard/service/mapreduce.js index 42f0c348ff..4e3a8efb94 100644 --- a/ambari-web/app/views/main/dashboard/service/mapreduce.js +++ b/ambari-web/app/views/main/dashboard/service/mapreduce.js @@ -107,7 +107,10 @@ App.MainDashboardServiceMapreduceView = App.MainDashboardServiceView.extend({ return App.Component.find().findProperty('componentName', 'TASKTRACKER'); }.property('components'), + isCollapsed: false, + toggleInfoView: function() { $('#mapreduce-info').toggle('blind', 200); + this.set('isCollapsed', !this.isCollapsed); } });
\ No newline at end of file diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js index f5f22d33ab..09cc1aad61 100644 --- a/ambari-web/app/views/main/service/info/summary.js +++ b/ambari-web/app/views/main/service/info/summary.js @@ -28,7 +28,8 @@ App.MainServiceInfoSummaryView = Em.View.extend({ hbase:false, zookeeper:false, oozie:false, - hive:false + hive:false, + ganglia:false }, data:{ @@ -38,6 +39,14 @@ App.MainServiceInfoSummaryView = Em.View.extend({ "user":"hive" } }, + gangliaServer:function(){ + var tmp=this.get('controller.content'); + if(tmp.get("id") == "GANGLIA"){ + return tmp.get("components").objectAt(0).get("host").get("id"); + }else{ + return ""; + } + }.property('controller.content'), service:function () { var svc = this.get('controller.content'); var svcName = svc.get('serviceName'); diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js index 9c75b5582f..ee70f5ed8b 100644 --- a/ambari-web/app/views/main/service/menu.js +++ b/ambari-web/app/views/main/service/menu.js @@ -66,7 +66,7 @@ App.MainServiceMenuView = Em.CollectionView.extend({ var allAlerts = App.router.get('clusterController.alerts'); var serviceId = this.get('content.serviceName'); if (serviceId) { - return allAlerts.filterProperty('serviceType', serviceId).length; + return allAlerts.filterProperty('serviceType', serviceId).filterProperty('isOk', false).length; } return 0; }.property('App.router.clusterController.alerts'), diff --git a/ambari-web/app/views/wizard/step1_view.js b/ambari-web/app/views/wizard/step1_view.js index 639c3c5998..e633cee739 100644 --- a/ambari-web/app/views/wizard/step1_view.js +++ b/ambari-web/app/views/wizard/step1_view.js @@ -21,6 +21,7 @@ var App = require('app'); App.WizardStep1View = Em.View.extend({ + tagName: "form", templateName: require('templates/wizard/step1'), didInsertElement: function () { @@ -31,6 +32,10 @@ App.WizardStep1View = Em.View.extend({ onError: function () { return this.get('controller.clusterNameError') !== ''; - }.property('controller.clusterNameError') + }.property('controller.clusterNameError'), + + submit: function(event) { + App.router.wizardStep1Controller.submit(); + } }); diff --git a/ambari-web/app/views/wizard/step3_view.js b/ambari-web/app/views/wizard/step3_view.js index c2ea51650c..d968b206a0 100644 --- a/ambari-web/app/views/wizard/step3_view.js +++ b/ambari-web/app/views/wizard/step3_view.js @@ -48,7 +48,7 @@ App.WizardHostView = Em.View.extend({ }.property(), isRetryable: function() { - return ['pending', 'error'].contains(this.get('hostInfo.bootStatus')); + return ['FAILED'].contains(this.get('hostInfo.bootStatus')); }.property('hostInfo.bootStatus') }); diff --git a/ambari-web/app/views/wizard/step8_view.js b/ambari-web/app/views/wizard/step8_view.js index a3915dc58d..aa708be896 100644 --- a/ambari-web/app/views/wizard/step8_view.js +++ b/ambari-web/app/views/wizard/step8_view.js @@ -26,5 +26,47 @@ App.WizardStep8View = Em.View.extend({ didInsertElement: function () { var controller = this.get('controller'); controller.loadStep(); - } + }, + + showLoadingIndicator: function(){ + if(!this.get('controller.isSubmitDisabled')){ + return; + } + + var opts = { + lines: 13, // The number of lines to draw + length: 7, // The length of each line + width: 4, // The line thickness + radius: 10, // The radius of the inner circle + corners: 1, // Corner roundness (0..1) + rotate: 0, // The rotation offset + color: '#000', // #rgb or #rrggbb + speed: 1, // Rounds per second + trail: 60, // Afterglow percentage + shadow: false, // Whether to render a shadow + hwaccel: false, // Whether to use hardware acceleration + className: 'spinner', // The CSS class to assign to the spinner + zIndex: 2e9, // The z-index (defaults to 2000000000) + top: 'auto', // Top position relative to parent in px + left: 'auto' // Left position relative to parent in px + }; + var target = $('#spinner')[0]; + var spinner = new Spinner(opts).spin(target); + + /*var el = $('#spinner').children('b'); + el.css('display', 'inline-block'); + var deg = 0; + var timeoutId = setInterval(function(){ + if(!$('#spinner').length){ + clearInterval(timeoutId); + } + deg += 15; + deg %= 360; + el.css('transform', 'rotate(' + deg + 'deg)'); + el.css('-ms-transform', 'rotate(' + deg + 'deg)'); + el.css('-o-transform', 'rotate(' + deg + 'deg)'); + el.css('-moz-transform', 'rotate(' + deg + 'deg)'); + el.css('-webkit-transform', 'rotate(' + deg + 'deg)'); + }, 80);*/ + }.observes('controller.isSubmitDisabled') }); diff --git a/ambari-web/vendor/scripts/spin.min.js b/ambari-web/vendor/scripts/spin.min.js new file mode 100644 index 0000000000..942980c82a --- /dev/null +++ b/ambari-web/vendor/scripts/spin.min.js @@ -0,0 +1,2 @@ +//fgnass.github.com/spin.js#v1.2.7 +!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t<n;t++)e.appendChild(arguments[t]);return e}function f(e,t,n,r){var o=["opacity",t,~~(e*100),n,r].join("-"),u=.01+n/r*100,f=Math.max(1-(1-e)/t*(100-u),e),l=s.substring(0,s.indexOf("Animation")).toLowerCase(),c=l&&"-"+l+"-"||"";return i[o]||(a.insertRule("@"+c+"keyframes "+o+"{"+"0%{opacity:"+f+"}"+u+"%{opacity:"+e+"}"+(u+.01)+"%{opacity:1}"+(u+t)%100+"%{opacity:"+e+"}"+"100%{opacity:"+f+"}"+"}",a.cssRules.length),i[o]=1),o}function l(e,t){var i=e.style,s,o;if(i[t]!==n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(o=0;o<r.length;o++){s=r[o]+t;if(i[s]!==n)return s}}function c(e,t){for(var n in t)e.style[l(e,n)||n]=t[n];return e}function h(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var i in r)e[i]===n&&(e[i]=r[i])}return e}function p(e){var t={x:e.offsetLeft,y:e.offsetTop};while(e=e.offsetParent)t.x+=e.offsetLeft,t.y+=e.offsetTop;return t}var r=["webkit","Moz","ms","O"],i={},s,a=function(){var e=o("style",{type:"text/css"});return u(t.getElementsByTagName("head")[0],e),e.sheet||e.styleSheet}(),d={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"auto",left:"auto",position:"relative"},v=function m(e){if(!this.spin)return new m(e);this.opts=h(e||{},m.defaults,d)};v.defaults={},h(v.prototype,{spin:function(e){this.stop();var t=this,n=t.opts,r=t.el=c(o(0,{className:n.className}),{position:n.position,width:0,zIndex:n.zIndex}),i=n.radius+n.length+n.width,u,a;e&&(e.insertBefore(r,e.firstChild||null),a=p(e),u=p(r),c(r,{left:(n.left=="auto"?a.x-u.x+(e.offsetWidth>>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n<t.lines;n++)r=c(o(),{position:"absolute",top:1+~(t.width/2)+"px",transform:t.hwaccel?"translate3d(0,0,0)":"",opacity:t.opacity,animation:s&&f(t.opacity,t.trail,n,t.lines)+" "+1/t.speed+"s linear infinite"}),t.shadow&&u(r,c(i("#000","0 0 4px #000"),{top:"2px"})),u(e,u(r,i(t.color,"0 0 1px rgba(0,0,0,.1)")));return e},opacity:function(e,t,n){t<e.childNodes.length&&(e.childNodes[t].style.opacity=n)}}),function(){function e(e,t){return o("<"+e+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r<i.childNodes.length&&(i=i.childNodes[t+r],i=i&&i.firstChild,i=i&&i.firstChild,i&&(i.opacity=n))}):s=l(t,"animation")}(),typeof define=="function"&&define.amd?define(function(){return v}):e.Spinner=v}(window,document);
\ No newline at end of file |