You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2014/07/28 19:47:12 UTC

git commit: AMBARI-6640 Memory leaks during tabs switching on "Customize Services" page. (Max Shepel via ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk 41bcd351e -> f3fa480cc


AMBARI-6640 Memory leaks during tabs switching on "Customize Services" page. (Max Shepel via ababiichuk)


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

Branch: refs/heads/trunk
Commit: f3fa480cc11e87105c5a8fff4e3b98f655c7c0b2
Parents: 41bcd35
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Mon Jul 28 20:44:51 2014 +0300
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Mon Jul 28 20:44:51 2014 +0300

----------------------------------------------------------------------
 .../templates/common/configs/service_config.hbs |  89 +---------------
 .../common/configs/service_config_category.hbs  | 101 +++++++++++++++++++
 .../common/configs/service_config_wizard.hbs    |  55 ++++++++++
 .../common/configs/services_config.hbs          |   3 +-
 .../app/views/common/configs/services_config.js |  62 +++++++++++-
 .../common/configs/services_config_test.js      |  59 +++++++++++
 6 files changed, 278 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/app/templates/common/configs/service_config.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/service_config.hbs b/ambari-web/app/templates/common/configs/service_config.hbs
index 66989a4..6e78fef 100644
--- a/ambari-web/app/templates/common/configs/service_config.hbs
+++ b/ambari-web/app/templates/common/configs/service_config.hbs
@@ -90,94 +90,7 @@
         {{view category.customView categoryBinding="category" serviceBinding="selectedService" canEditBinding="view.canEdit" serviceConfigsBinding="selectedService.configs"}}
       {{/if}}
     {{else}}
-    {{#view App.ServiceConfigsByCategoryView categoryBinding="category" canEditBinding="view.canEdit" serviceBinding="selectedService" serviceConfigsBinding="selectedService.configs" supportsHostOverridesBinding="view.supportsHostOverrides"}}
-
-            <div class="accordion-heading" {{action "onToggleBlock" category target="view"}}>
-                <i {{bindAttr class=":pull-left :accordion-toggle category.isCollapsed:icon-caret-right:icon-caret-down"}}></i>
-                <a class="accordion-toggle">{{category.displayName}}</a>
-            </div>
-
-            <div class="accordion-body collapse in" {{bindAttr style="view.isCategoryBodyVisible"}}>
-              <div class="accordion-inner service-config-section">
-                <form class="form-horizontal" autocomplete="off">
-
-                  {{#each view.filteredCategoryConfigs}}
-                      <div {{bindAttr class=":entry-row isOverridden:overridden-property isComparison:overridden-property"}}>
-                          {{#if showLabel}}
-                            <span {{bindAttr class="errorMessage:error: :control-group :control-label-span"}}>
-                              <label class="control-label">
-                                {{formatWordBreak displayName}}
-                                {{#if App.supports.secureCluster}}
-                                  {{#if isSecureConfig}}
-                                    <a href="javascript:void(null);"><i class="icon-lock" rel="tooltip" data-toggle="tooltip" title="security knob"></i></a>
-                                  {{/if}}
-                                {{/if}}
-                                {{#if view.supportsHostOverrides}}
-                                  {{#if isRestartRequired}}
-                                    <i class="icon-refresh restart-required-property" rel="tooltip" {{bindAttr title="restartRequiredMessage"}}></i>
-                                  {{/if}}
-                                {{/if}}
-                              </label>
-                            </span>
-                          {{/if}}
-                          <div {{bindAttr class="showLabel:controls"}}>
-                            {{! Here serviceConfigBinding should ideally be serviceConfigPropertyBinding }}
-                              <div {{bindAttr class="errorMessage:error: warnMessage:warning: :control-group"}}>
-                                {{view viewClass serviceConfigBinding="this" categoryConfigsAllBinding="view.categoryConfigsAll" }}
-                                {{#if view.canEdit}}
-	                                {{#if isPropertyOverridable}}
-                                    {{#if view.supportsHostOverrides}}
-                                      {{#if App.isAdmin}}
-	                                    <a class="action" {{action "createOverrideProperty" this target="view" }} ><i class="icon-plus-sign"></i>{{t common.override}}</a>
-                                      {{/if}}
-                                    {{/if}}
-	                                {{/if}}
-	                                {{#unless cantBeUndone}}
-	                                  {{#if isNotDefaultValue}}
-	                                      <a class="action" {{action "doRestoreDefaultValue" this target="view" }} ><i class="icon-undo"></i>{{t common.undo}}</a>
-	                                  {{/if}}
-	                                {{/unless}}
-	                                {{#if isRemovable}}
-                                    {{#if App.isAdmin}}
-	                                    <a class="action" {{action "removeProperty" this target="view" }} ><i class="icon-minus-sign"></i>{{t common.remove}}</a>
-                                    {{/if}}
-	                                {{/if}}
-                                  {{#if supportsFinal}}
-                                    <label class="checkbox inline">{{view Ember.Checkbox checkedBinding="isFinal"}}{{t services.service.config.final}}</label>
-                                  {{/if}}
-                                {{/if}}
-                                  <span class="help-inline">{{errorMessage}}</span>
-                                  <span class="help-inline">{{warnMessage}}</span>
-                              </div>
-                            {{#if this.isOverridden}}
-                              {{view App.ServiceConfigView.SCPOverriddenRowsView serviceConfigPropertyBinding="this" isDefaultGroupSelectedBinding="controller.selectedConfigGroup.isDefault"}}
-                            {{/if}}
-                            {{#if this.isComparison}}
-                              {{view App.ServiceConfigView.SCPComparisonRowsView serviceConfigPropertyBinding="this"}}
-                            {{/if}}
-                          </div>
-                      </div>
-                    {{#if this.additionalView}}
-                      {{view additionalView}}
-                    {{/if}}
-                  {{/each}}
-
-                  {{! For Advanced, Advanced Core Site, Advanced HDFS Site sections, show the 'Add Property' link.}}
-                  {{#if App.isAdmin}}
-                    {{#if view.canEdit}}
-                      {{#if category.customCanAddProperty }}
-                        <div>
-                          <a href="#" {{action "showAddPropertyWindow" this target="view" }} >{{t installer.step7.config.addProperty}}...</a>
-                        </div>
-                      {{/if}}
-                    {{/if}}
-                  {{/if}}
-                </form>
-              </div>
-            </div>
-
-
-    {{/view}}
+      {{view App.ServiceConfigsByCategoryView categoryBinding="category" canEditBinding="view.canEdit" serviceBinding="selectedService" serviceConfigsBinding="selectedService.configs" supportsHostOverridesBinding="view.supportsHostOverrides"}}
     {{/if}}
   {{/each}}
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/app/templates/common/configs/service_config_category.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/service_config_category.hbs b/ambari-web/app/templates/common/configs/service_config_category.hbs
new file mode 100644
index 0000000..ecc380c
--- /dev/null
+++ b/ambari-web/app/templates/common/configs/service_config_category.hbs
@@ -0,0 +1,101 @@
+{{!
+* 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="accordion-heading" {{action "onToggleBlock" category target="view"}}>
+  <i {{bindAttr class=":pull-left :accordion-toggle view.category.isCollapsed:icon-caret-right:icon-caret-down"}}></i>
+  <a class="accordion-toggle">{{view.category.displayName}}</a>
+</div>
+
+<div class="accordion-body collapse in" {{bindAttr style="view.isCategoryBodyVisible"}}>
+  <div class="accordion-inner service-config-section">
+    <form class="form-horizontal" autocomplete="off">
+
+      {{#each view.filteredCategoryConfigs}}
+        <div {{bindAttr class=":entry-row isOverridden:overridden-property isComparison:overridden-property"}}>
+          {{#if showLabel}}
+            <span {{bindAttr class="errorMessage:error: :control-group :control-label-span"}}>
+                              <label class="control-label">
+                                {{formatWordBreak displayName}}
+                                {{#if App.supports.secureCluster}}
+                                  {{#if isSecureConfig}}
+                                    <a href="javascript:void(null);"><i class="icon-lock" rel="tooltip" data-toggle="tooltip" title="security knob"></i></a>
+                                  {{/if}}
+                                {{/if}}
+                                {{#if view.supportsHostOverrides}}
+                                  {{#if isRestartRequired}}
+                                    <i class="icon-refresh restart-required-property" rel="tooltip" {{bindAttr title="restartRequiredMessage"}}></i>
+                                  {{/if}}
+                                {{/if}}
+                              </label>
+                            </span>
+          {{/if}}
+          <div {{bindAttr class="showLabel:controls"}}>
+            {{! Here serviceConfigBinding should ideally be serviceConfigPropertyBinding }}
+            <div {{bindAttr class="errorMessage:error: warnMessage:warning: :control-group"}}>
+              {{view viewClass serviceConfigBinding="this" categoryConfigsAllBinding="view.categoryConfigsAll" }}
+              {{#if view.canEdit}}
+                {{#if isPropertyOverridable}}
+                  {{#if view.supportsHostOverrides}}
+                    {{#if App.isAdmin}}
+                      <a class="action" {{action "createOverrideProperty" this target="view" }} ><i class="icon-plus-sign"></i>{{t common.override}}</a>
+                    {{/if}}
+                  {{/if}}
+                {{/if}}
+                {{#unless cantBeUndone}}
+                  {{#if isNotDefaultValue}}
+                    <a class="action" {{action "doRestoreDefaultValue" this target="view" }} ><i class="icon-undo"></i>{{t common.undo}}</a>
+                  {{/if}}
+                {{/unless}}
+                {{#if isRemovable}}
+                  {{#if App.isAdmin}}
+                    <a class="action" {{action "removeProperty" this target="view" }} ><i class="icon-minus-sign"></i>{{t common.remove}}</a>
+                  {{/if}}
+                {{/if}}
+                {{#if supportsFinal}}
+                  <label class="checkbox inline">{{view Ember.Checkbox checkedBinding="isFinal"}}{{t services.service.config.final}}</label>
+                {{/if}}
+              {{/if}}
+              <span class="help-inline">{{errorMessage}}</span>
+              <span class="help-inline">{{warnMessage}}</span>
+            </div>
+            {{#if this.isOverridden}}
+              {{view App.ServiceConfigView.SCPOverriddenRowsView serviceConfigPropertyBinding="this" isDefaultGroupSelectedBinding="controller.selectedConfigGroup.isDefault"}}
+            {{/if}}
+            {{#if this.isComparison}}
+              {{view App.ServiceConfigView.SCPComparisonRowsView serviceConfigPropertyBinding="this"}}
+            {{/if}}
+          </div>
+        </div>
+        {{#if this.additionalView}}
+          {{view additionalView}}
+        {{/if}}
+      {{/each}}
+
+      {{! For Advanced, Advanced Core Site, Advanced HDFS Site sections, show the 'Add Property' link.}}
+      {{#if App.isAdmin}}
+        {{#if view.canEdit}}
+          {{#if view.category.customCanAddProperty }}
+            <div>
+              <a href="#" {{action "showAddPropertyWindow" this target="view" }} >{{t installer.step7.config.addProperty}}...</a>
+            </div>
+          {{/if}}
+        {{/if}}
+      {{/if}}
+    </form>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/app/templates/common/configs/service_config_wizard.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/service_config_wizard.hbs b/ambari-web/app/templates/common/configs/service_config_wizard.hbs
new file mode 100644
index 0000000..8bf7429
--- /dev/null
+++ b/ambari-web/app/templates/common/configs/service_config_wizard.hbs
@@ -0,0 +1,55 @@
+{{!
+* 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.
+}}
+
+{{#if view.supportsHostOverrides}}
+  <div class="alert alert-info">
+    {{t common.group}}&nbsp;
+	  <span class="btn-group">
+		  <button {{bindAttr disabled="controller.isHostsConfigsPage"}} class="btn">{{selectedConfigGroup.displayNameHosts}}</button>
+		  <button {{bindAttr disabled="controller.isHostsConfigsPage"}} class="btn dropdown-toggle" data-toggle="dropdown">
+        <span class="caret"></span>
+      </button>
+		  <ul class="dropdown-menu">
+        <!-- available config group menu links -->
+        {{#each configGroup in configGroups}}
+          <li>
+            <a href="#" {{action "selectConfigGroup" configGroup target="controller"}}>
+              {{configGroup.displayNameHosts}}
+            </a>
+          </li>
+        {{/each}}
+      </ul>
+		</span>
+    {{#if App.isAdmin}}
+      {{#if controller.isHostsConfigsPage}}
+        &nbsp;<a href="#" {{action "switchHostGroup" target="controller"}}>{{t common.change}}</a>
+      {{else}}
+        <a href="#"  class="link-left-pad" {{action "manageConfigurationGroup" target="controller"}}>{{t services.service.actions.manage_configuration_groups.short}}</a>
+      {{/if}}
+    {{/if}}
+    <div class="pull-right">
+      {{view App.FilterComboCleanableView filterBinding="view.filter" columnsBinding="view.columns" popoverDescriptionBinding="view.propertyFilterPopover"}}
+    </div>
+  </div>
+{{/if}}
+
+<div class="accordion">
+  {{#each catView in view.serviceConfigsByCategoryView.childViews}}
+    {{view catView}}
+  {{/each}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/app/templates/common/configs/services_config.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/services_config.hbs b/ambari-web/app/templates/common/configs/services_config.hbs
index 516406f..5030566 100644
--- a/ambari-web/app/templates/common/configs/services_config.hbs
+++ b/ambari-web/app/templates/common/configs/services_config.hbs
@@ -28,7 +28,8 @@
     {{/if}}
   {{/each}}
 </ul>
-{{view App.ServiceConfigView isNotEditableBinding="controller.isNotEditable" filterBinding="controller.filter" columnsBinding="controller.filterColumns"}}
+{{view App.ServiceConfigContainerView}}
+<p class="loading align-center"></p>
 {{#if isSubmitDisabled}}
   <div class="alert">{{t installer.step7.attentionNeeded}}</div>
 {{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/app/views/common/configs/services_config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/services_config.js b/ambari-web/app/views/common/configs/services_config.js
index 0dc0529..2676f1f 100644
--- a/ambari-web/app/views/common/configs/services_config.js
+++ b/ambari-web/app/views/common/configs/services_config.js
@@ -60,7 +60,9 @@ App.ServiceConfigView = Em.View.extend({
     if(this.get('isNotEditable') === true) {
       this.set('canEdit', false);
     }
-    this.$('.service-body').hide();
+    if (this.$('.service-body')) {
+      this.$('.service-body').hide();
+    }
     App.tooltip($(".restart-required-property"), {html: true});
     App.tooltip($(".icon-lock"), {placement: 'right'});
     this.checkCanEdit();
@@ -95,6 +97,8 @@ App.ServiceConfigView = Em.View.extend({
 
 App.ServiceConfigsByCategoryView = Ember.View.extend(App.UserPref, {
 
+  templateName: require('templates/common/configs/service_config_category'),
+
   classNames: ['accordion-group', 'common-config-category'],
   classNameBindings: ['category.name', 'isShowBlock::hidden'],
 
@@ -375,7 +379,7 @@ App.ServiceConfigsByCategoryView = Ember.View.extend(App.UserPref, {
     var categoryBlock = $('.' + this.get('category.name').split(' ').join('.') + '>.accordion-body');
     filteredResult.length && !this.get('category.isCollapsed') ? categoryBlock.show() : categoryBlock.hide();
     return filteredResult;
-  }.property('categoryConfigs', 'parentView.filter', 'parentView.columns.@each.selected'),
+  }.property('categoryConfigs', 'parentView.filter', 'parentView.columns.@each.selected').cacheable(),
 
   /**
    * sort configs in current category by index
@@ -725,6 +729,60 @@ App.ServiceConfigsByCategoryView = Ember.View.extend(App.UserPref, {
   }
 });
 
+App.ServiceConfigContainerView = Em.ContainerView.extend({
+  view: null,
+  pushView: function () {
+    if (this.get('controller.selectedService')) {
+      var self = this;
+      var controllerRoute = 'App.router.' + this.get('controller.name');
+      if (!this.get('view')) {
+        this.get('childViews').pushObject(App.ServiceConfigView.create({
+          templateName: require('templates/common/configs/service_config_wizard'),
+          controllerBinding: controllerRoute,
+          isNotEditableBinding: controllerRoute + '.isNotEditable',
+          filterBinding: controllerRoute + '.filter',
+          columnsBinding: controllerRoute + '.filterColumns',
+          selectedServiceBinding: controllerRoute + '.selectedService',
+          serviceConfigsByCategoryView: Em.ContainerView.create(),
+          willDestroyElement: function () {
+            $('.loading').append(Em.I18n.t('app.loadingPlaceholder'));
+          },
+          didInsertElement: function () {
+            $('.loading').empty();
+            this._super();
+          }
+        }));
+      } else {
+        this.get('childViews').pushObject(this.get('view'));
+      }
+      this.get('controller.selectedService.configCategories').forEach(function (item) {
+        var categoryView = item.get('isCustomView') ? (App.get('supports.capacitySchedulerUi') ? item.get('customView') : null) : App.ServiceConfigsByCategoryView;
+        if (categoryView !== null) {
+          self.get('childViews.lastObject.serviceConfigsByCategoryView.childViews').pushObject(categoryView.extend({
+            category: item,
+            controllerBinding: controllerRoute,
+            canEditBinding: 'parentView.canEdit',
+            serviceBinding: controllerRoute + '.selectedService',
+            serviceConfigsBinding: controllerRoute + '.selectedService.configs',
+            supportsHostOverridesBinding: 'parentView.supportsHostOverrides'
+          }));
+        }
+      });
+    }
+  },
+  selectedServiceObserver: function () {
+    if (this.get('childViews.length')) {
+      var view = this.get('childViews.firstObject');
+      if (view.get('serviceConfigsByCategoryView.childViews.length')) {
+        view.get('serviceConfigsByCategoryView.childViews').clear();
+      }
+      view.removeFromParent();
+      this.set('view', view);
+    }
+    this.pushView();
+  }.observes('controller.selectedService')
+});
+
 App.ServiceConfigTab = Ember.View.extend({
 
   tagName: 'li',

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3fa480c/ambari-web/test/views/common/configs/services_config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/configs/services_config_test.js b/ambari-web/test/views/common/configs/services_config_test.js
index b78a872..2014dea 100644
--- a/ambari-web/test/views/common/configs/services_config_test.js
+++ b/ambari-web/test/views/common/configs/services_config_test.js
@@ -242,3 +242,62 @@ describe('App.ServiceConfigsByCategoryView', function () {
     })
   })
 });
+
+describe('App.ServiceConfigContainerView', function () {
+  var view,
+    selectedService = {
+      configCategories: []
+    };
+  beforeEach(function () {
+    view = App.ServiceConfigContainerView.create();
+  });
+  describe('#pushView', function () {
+    it('shouldn\'t be launched before selectedService is set', function () {
+      view.set('controller', {});
+      view.pushView();
+      expect(view.get('childViews')).to.be.empty;
+    });
+  });
+  describe('#selectedServiceObserver', function () {
+    it('should add a child view', function () {
+      view.set('controller', {
+        selectedService: {
+          configCategories: []
+        }
+      });
+      expect(view.get('childViews')).to.have.length(1);
+    });
+    it('should set controller for the view', function () {
+      view.set('controller', {
+        name: 'controller',
+        selectedService: {
+          configCategories: []
+        }
+      });
+      expect(view.get('childViews.firstObject.controller.name')).to.equal('controller');
+    });
+    it('should add config categories', function () {
+      view.set('controller', {
+        selectedService: {
+          configCategories: [Em.Object.create(), Em.Object.create()]
+        }
+      });
+      expect(view.get('childViews.firstObject.serviceConfigsByCategoryView.childViews')).to.have.length(2);
+    });
+    it('shouldn\'t add category with custom view if capacitySchedulerUi isn\'t active', function () {
+      sinon.stub(App, 'get', function(k) {
+        if (k === 'supports.capacitySchedulerUi') return false;
+        return Em.get(App, k);
+      });
+      view.set('controller', {
+        selectedService: {
+          configCategories: [Em.Object.create({
+            isCustomView: true
+          })]
+        }
+      });
+      expect(view.get('childViews.firstObject.serviceConfigsByCategoryView.childViews')).to.be.empty;
+      App.get.restore();
+    });
+  });
+});