Repository: ambari Updated Branches: refs/heads/trunk 7c3bcc9e8 -> bb7ed8952
AMBARI-19921. Js errors appear when user try to delete widgets from dashboard (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/bb7ed895 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/bb7ed895 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/bb7ed895 Branch: refs/heads/trunk Commit: bb7ed895212845201cbc1a159a10b6395f48bf51 Parents: 7c3bcc9 Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Wed Feb 8 14:13:38 2017 +0200 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Thu Feb 9 11:22:45 2017 +0200 ---------------------------------------------------------------------- .../app/templates/main/dashboard/widgets.hbs | 10 +- ambari-web/app/views/main/dashboard/widget.js | 11 +- ambari-web/app/views/main/dashboard/widgets.js | 116 ++++++++----- .../test/views/main/dashboard/widget_test.js | 21 +-- .../test/views/main/dashboard/widgets_test.js | 161 +++++++++++++++---- 5 files changed, 221 insertions(+), 98 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/bb7ed895/ambari-web/app/templates/main/dashboard/widgets.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/dashboard/widgets.hbs b/ambari-web/app/templates/main/dashboard/widgets.hbs index 8e04f1c..4b7a269 100644 --- a/ambari-web/app/templates/main/dashboard/widgets.hbs +++ b/ambari-web/app/templates/main/dashboard/widgets.hbs @@ -47,11 +47,11 @@ <div class="dashboard-widgets-box"> <div id="dashboard-widgets" class="widgets-container"> <div class="thumbnails" id="sortable"> - {{#if view.visibleWidgets.length}} - {{#each widget in view.visibleWidgets}} - {{view widget.viewClass widgetBinding="widget"}} - {{/each}} - {{/if}} + {{#each widget in view.allWidgets}} + {{#if widget.isVisible}} + {{view widget.viewClass widgetBinding="widget"}} + {{/if}} + {{/each}} </div> </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/bb7ed895/ambari-web/app/views/main/dashboard/widget.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widget.js b/ambari-web/app/views/main/dashboard/widget.js index cacac1a..e7a626c 100644 --- a/ambari-web/app/views/main/dashboard/widget.js +++ b/ambari-web/app/views/main/dashboard/widget.js @@ -186,16 +186,7 @@ App.DashboardWidgetView = Em.View.extend({ * delete widget */ deleteWidget: function () { - var parent = this.get('parentView'); - var userPreferences = parent.get('userPreferences'); - var deletedId = this.get('id'); - var newValue = { - visible: userPreferences.visible.slice(0).without(deletedId), - hidden: userPreferences.hidden.concat([deletedId]), - threshold: userPreferences.threshold - }; - parent.saveWidgetsSettings(newValue); - parent.renderWidgets(); + this.get('parentView').hideWidget(this.get('id')); }, /** http://git-wip-us.apache.org/repos/asf/ambari/blob/bb7ed895/ambari-web/app/views/main/dashboard/widgets.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widgets.js b/ambari-web/app/views/main/dashboard/widgets.js index 0c6b7aa..572625d 100644 --- a/ambari-web/app/views/main/dashboard/widgets.js +++ b/ambari-web/app/views/main/dashboard/widgets.js @@ -17,7 +17,16 @@ */ var App = require('app'); -var filters = require('views/common/filter_view'); + +const WidgetObject = Em.Object.extend({ + id: '', + threshold: '', + viewClass: null, + sourceName: '', + title: '', + checked: false, + isVisible: true +}); App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, App.TimeRangeMixin, { name: 'mainDashboardWidgetsView', @@ -202,6 +211,10 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap } ], + widgetsDefinitionMap: function () { + return this.get('widgetsDefinition').toMapByProperty('id'); + }.property('widgetsDefinition.[]'), + /** * List of services * @type {Ember.Enumerable} @@ -226,16 +239,23 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap isMoving: false, /** + * @type {WidgetObject[]} + */ + allWidgets: [], + + /** * List of visible widgets - * @type {Ember.Enumerable} + * + * @type {WidgetObject[]} */ - visibleWidgets: [], + visibleWidgets: Em.computed.filterBy('allWidgets', 'isVisible', true), /** * List of hidden widgets - * @type {Ember.Enumerable} + * + * @type {WidgetObject[]} */ - hiddenWidgets: [], // widget child view will push object in this array if deleted + hiddenWidgets: Em.computed.filterBy('allWidgets', 'isVisible', false), timeRangeClassName: 'pull-left', @@ -276,12 +296,30 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap /** * make POST call to save settings - * @param {object} settings + * format settings if they are not provided + * + * @param {object} [settings] */ saveWidgetsSettings: function (settings) { - this.set('userPreferences', settings); - this.setDBProperty(this.get('persistKey'), settings); - this.postUserPref(this.get('persistKey'), settings); + let userPreferences = this.get('userPreferences'); + let newSettings = { + visible: [], + hidden: [], + threshold: {} + }; + if (arguments.length === 1) { + newSettings = settings; + } + else { + newSettings.threshold = userPreferences.threshold; + this.get('allWidgets').forEach(widget => { + let key = widget.get('isVisible') ? 'visible' : 'hidden'; + newSettings[key].push(widget.get('id')); + }); + } + this.set('userPreferences', newSettings); + this.setDBProperty(this.get('persistKey'), newSettings); + this.postUserPref(this.get('persistKey'), newSettings); }, getUserPrefSuccessCallback: function (response) { @@ -301,7 +339,7 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap var clusterEnv = App.router.get('clusterController.clusterEnv').properties; var yarnMemoryWidget = widgetsDefinition.findProperty('id', 20); - if (clusterEnv['hide_yarn_memory_widget'] === 'true') { + if (clusterEnv.hide_yarn_memory_widget === 'true') { yarnMemoryWidget.isHiddenByDefault = true; } }, @@ -331,36 +369,42 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap }, /** - * set widgets to view in order to render + * Don't show widget on the Dashboard + * + * @param {number} id */ - renderWidgets: function () { - var widgetsDefinitionMap = this.get('widgetsDefinition').toMapByProperty('id'); - var userPreferences = this.get('userPreferences'); - var visibleWidgets = []; - var hiddenWidgets = []; - - userPreferences.visible.forEach(function(id) { - var widget = widgetsDefinitionMap[id]; - visibleWidgets.push(Em.Object.create({ - id: id, - threshold: userPreferences.threshold[id], - viewClass: App[widget.viewName], - sourceName: widget.sourceName, - title: widget.title - })); - }); + hideWidget(id) { + this.get('allWidgets').findProperty('id', id).set('isVisible', false); + this.saveWidgetsSettings(); + }, - userPreferences.hidden.forEach(function(id) { - var widget = widgetsDefinitionMap[id]; - hiddenWidgets.push(Em.Object.create({ - id: id, - title: widget.title, - checked: false - })); + /** + * + * @param {number} id + * @param {boolean} isVisible + * @returns {WidgetObject} + * @private + */ + _createWidgetObj(id, isVisible) { + var widget = this.get('widgetsDefinitionMap')[id]; + return WidgetObject.create({ + id, + threshold: this.get('userPreferences.threshold')[id], + viewClass: App[widget.viewName], + sourceName: widget.sourceName, + title: widget.title, + isVisible }); + }, - this.set('visibleWidgets', visibleWidgets); - this.set('hiddenWidgets', hiddenWidgets); + /** + * set widgets to view in order to render + */ + renderWidgets: function () { + var userPreferences = this.get('userPreferences'); + var newVisibleWidgets = userPreferences.visible.map(id => this._createWidgetObj(id, true)); + var newHiddenWidgets = userPreferences.hidden.map(id => this._createWidgetObj(id, false)); + this.set('allWidgets', newVisibleWidgets.concat(newHiddenWidgets)); }, /** http://git-wip-us.apache.org/repos/asf/ambari/blob/bb7ed895/ambari-web/test/views/main/dashboard/widget_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/dashboard/widget_test.js b/ambari-web/test/views/main/dashboard/widget_test.js index 8582ad0..a504c6d 100644 --- a/ambari-web/test/views/main/dashboard/widget_test.js +++ b/ambari-web/test/views/main/dashboard/widget_test.js @@ -19,6 +19,7 @@ var App = require('app'); require('views/main/dashboard/widget'); +var dashboard = App.MainDashboardWidgetsView.create(); describe('App.DashboardWidgetView', function () { var view; @@ -28,7 +29,10 @@ describe('App.DashboardWidgetView', function () { widget: Em.Object.create(), parentView: Em.Object.create({ userPreferences: {}, - saveWidgetsSettings: Em.K, + setDBProperty: Em.K, + postUserPref: Em.K, + hideWidget: dashboard.hideWidget, + saveWidgetsSettings: dashboard.saveWidgetsSettings, renderWidgets: Em.K }) }); @@ -223,8 +227,7 @@ describe('App.DashboardWidgetView', function () { describe('#deleteWidget()', function() { beforeEach(function() { - sinon.stub(view.get('parentView'), 'saveWidgetsSettings'); - sinon.stub(view.get('parentView'), 'renderWidgets'); + view.get('parentView').set('allWidgets', [Em.Object.create({id: 1, isVisible: true})]); view.set('widget.id', 1); view.set('parentView.userPreferences', { visible: [1], @@ -234,22 +237,14 @@ describe('App.DashboardWidgetView', function () { view.deleteWidget(); }); - afterEach(function() { - view.get('parentView').saveWidgetsSettings.restore(); - view.get('parentView').renderWidgets.restore(); - }); - - it('saveWidgetsSettings should be called', function() { - expect(view.get('parentView').saveWidgetsSettings.getCall(0).args[0]).to.be.eql({ + it('userPreferences are set correctly', function() { + expect(view.get('parentView.userPreferences')).to.be.eql({ visible: [], hidden: [1], threshold: [] }); }); - it('renderWidgets should be called', function() { - expect(view.get('parentView').renderWidgets).to.be.calledOnce; - }); }); describe('#editWidget()', function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/bb7ed895/ambari-web/test/views/main/dashboard/widgets_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/dashboard/widgets_test.js b/ambari-web/test/views/main/dashboard/widgets_test.js index b2d154b..5d1ddb2 100644 --- a/ambari-web/test/views/main/dashboard/widgets_test.js +++ b/ambari-web/test/views/main/dashboard/widgets_test.js @@ -90,10 +90,12 @@ describe('App.MainDashboardWidgetsView', function () { describe('#saveWidgetsSettings()', function() { - beforeEach(function() { - sinon.stub(view, 'setDBProperty'); - sinon.stub(view, 'postUserPref'); - view.saveWidgetsSettings({settings:{}}); + var userPreferences = {visible: [], hidden: [], threshold: {}}; + + beforeEach(function () { + sinon.stub(view, 'setDBProperty', Em.K); + sinon.stub(view, 'postUserPref', Em.K); + view.set('userPreferences', userPreferences); }); afterEach(function() { @@ -101,17 +103,61 @@ describe('App.MainDashboardWidgetsView', function () { view.postUserPref.restore(); }); - it('setDBProperty should be called', function() { - expect(view.setDBProperty.calledWith('key', {settings:{}})).to.be.true; - }); + describe('called with arg', function () { + + beforeEach(function() { + view.saveWidgetsSettings({settings:{}}); + }); + + it('setDBProperty should be called', function() { + expect(view.setDBProperty.calledWith('key', {settings:{}})).to.be.true; + }); + + it('postUserPref should be called', function() { + expect(view.postUserPref.calledWith('key', {settings:{}})).to.be.true; + }); + + it('userPreferences should be set', function() { + expect(view.get('userPreferences')).to.be.eql({settings:{}}); + }); - it('postUserPref should be called', function() { - expect(view.postUserPref.calledWith('key', {settings:{}})).to.be.true; }); - it('userPreferences should be set', function() { - expect(view.get('userPreferences')).to.be.eql({settings:{}}); + describe('called without args', function () { + + var allWidgets = [ + Em.Object.create({id: 1, isVisible: true}), + Em.Object.create({id: 2, isVisible: true}), + Em.Object.create({id: 3, isVisible: false}), + Em.Object.create({id: 4, isVisible: false}) + ]; + + var expectedUserSettings = { + visible: [1, 2], + hidden: [3, 4], + threshold: {} + }; + + beforeEach(function () { + view.set('userPreferences', userPreferences); + view.set('allWidgets', allWidgets); + view.saveWidgetsSettings(); + }); + + it('setDBProperty should be called', function() { + expect(view.setDBProperty.calledWith('key', expectedUserSettings)).to.be.true; + }); + + it('postUserPref should be called', function() { + expect(view.postUserPref.calledWith('key', expectedUserSettings)).to.be.true; + }); + + it('userPreferences should be set', function() { + expect(view.get('userPreferences')).to.be.eql(expectedUserSettings); + }); + }); + }); describe('#getUserPrefSuccessCallback()', function() { @@ -210,30 +256,77 @@ describe('App.MainDashboardWidgetsView', function () { describe('#renderWidgets()', function() { - it('should set visibleWidgets and hiddenWidgets', function() { - view.set('userPreferences', { - visible: [1], - hidden: [2], - threshold: { - 1: [], - 2: [1,2] - } + describe('should set visibleWidgets and hiddenWidgets', function() { + + beforeEach(function () { + view.set('userPreferences', { + visible: [1], + hidden: [2], + threshold: { + 1: [], + 2: [1,2] + } + }); + view.renderWidgets(); + }); + + describe('visibleWidgets', function () { + var widget; + + beforeEach(function () { + widget = view.get('visibleWidgets')[0]; + }); + + it('one visible widget', function () { + expect(view.get('visibleWidgets.length')).to.be.equal(1); + }); + + it('id', function () { + expect(widget.get('id')).to.be.equal(1); + }); + + it('threshold', function () { + expect(widget.get('threshold')).to.be.eql([]); + }); + + it('viewClass', function () { + expect(widget.get('viewClass')).to.be.eql(App.NameNodeHeapPieChartView); + }); + + it('sourceName', function () { + expect(widget.get('sourceName')).to.be.equal('HDFS'); + }); + + it('title', function () { + expect(widget.get('title')).to.be.equal(Em.I18n.t('dashboard.widgets.NameNodeHeap')); + }); + + }); + + describe('hiddenWidgets', function () { + var widget; + + beforeEach(function () { + widget = view.get('hiddenWidgets')[0]; + }); + + it('one hidden widget', function () { + expect(view.get('hiddenWidgets.length')).to.be.equal(1); + }); + + it('id', function () { + expect(widget.get('id')).to.be.equal(2); + }); + + it('checked', function () { + expect(widget.get('checked')).to.be.equal(false); + }); + + it('title', function () { + expect(widget.get('title')).to.be.equal(Em.I18n.t('dashboard.widgets.HDFSDiskUsage')); + }); + }); - view.renderWidgets(); - expect(view.get('visibleWidgets')).to.be.eql([Em.Object.create({ - id: 1, - threshold: [], - viewClass: App.NameNodeHeapPieChartView, - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.NameNodeHeap') - })]); - expect(view.get('hiddenWidgets')).to.be.eql([ - Em.Object.create({ - id: 2, - title: Em.I18n.t('dashboard.widgets.HDFSDiskUsage'), - checked: false - }) - ]); }); });