Repository: ambari Updated Branches: refs/heads/trunk 9301f9b16 -> 12598cff5
AMBARI-10293 Implement Actions Dropdown menu for the widgets on service summary page. (atkach) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/12598cff Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/12598cff Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/12598cff Branch: refs/heads/trunk Commit: 12598cff5876fe4a2323828722a5869ed5373f97 Parents: 9301f9b Author: Andrii Tkach <[email protected]> Authored: Tue Mar 31 19:12:33 2015 +0300 Committer: Andrii Tkach <[email protected]> Committed: Tue Mar 31 21:19:00 2015 +0300 ---------------------------------------------------------------------- .../data/widget_layouts/HBASE/layouts.json | 16 +++++ .../data/widget_layouts/HBASE/stack_layout.json | 3 + .../controllers/main/service/info/summary.js | 76 +++++++++++++++++++- ambari-web/app/mappers.js | 1 + ambari-web/app/mappers/widget_layout_mapper.js | 29 ++++++++ ambari-web/app/mappers/widget_mapper.js | 3 +- ambari-web/app/messages.js | 3 + ambari-web/app/mixins/common/widget_mixin.js | 26 +++++-- ambari-web/app/models.js | 3 +- ambari-web/app/models/widget.js | 2 +- ambari-web/app/models/widget_layout.js | 6 +- .../app/styles/enhanced_service_dashboard.less | 47 +++++++++++- ambari-web/app/styles/widget_layout.less | 46 ------------ .../templates/common/widget/gauge_widget.hbs | 8 ++- .../templates/common/widget/template_widget.hbs | 8 ++- .../app/templates/main/service/info/summary.hbs | 42 ++++++++++- ambari-web/app/utils/ajax/ajax.js | 5 ++ .../views/common/widget/gauge_widget_view.js | 4 +- .../views/common/widget/graph_widget_view.js | 2 +- .../views/common/widget/template_widget_view.js | 2 +- .../app/views/main/service/info/summary.js | 53 ++++++++++++++ .../test/mixins/common/widget_mixin_test.js | 12 ++-- 22 files changed, 323 insertions(+), 74 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/assets/data/widget_layouts/HBASE/layouts.json ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/data/widget_layouts/HBASE/layouts.json b/ambari-web/app/assets/data/widget_layouts/HBASE/layouts.json new file mode 100644 index 0000000..ae33a84 --- /dev/null +++ b/ambari-web/app/assets/data/widget_layouts/HBASE/layouts.json @@ -0,0 +1,16 @@ +{ + "href": "http://c6401.ambari.apache.org:8080/api/v1/users?widget_layouts/section_name=HBASE_SUMMARY&widget_layouts/scope=CLUSTER", + "items": [ + { + "href": "http://c6401.ambari.apache.org:8080/api/v1/users/jaimin", + "Users": { + "user_name": "jaimin" + }, + "widget_layouts": { + "layout_name": "default_hbase_layout", + "section_name": "HBASE_SUMMARY", + "scope": "CLUSTER" + } + } + ] +} http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/assets/data/widget_layouts/HBASE/stack_layout.json ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/data/widget_layouts/HBASE/stack_layout.json b/ambari-web/app/assets/data/widget_layouts/HBASE/stack_layout.json index 6285138..bfab170 100644 --- a/ambari-web/app/assets/data/widget_layouts/HBASE/stack_layout.json +++ b/ambari-web/app/assets/data/widget_layouts/HBASE/stack_layout.json @@ -17,6 +17,7 @@ "display_name": "RegionServer Reads and Writes", "description": "This widget shows all the read requests and write requests on all regions for a RegionServer", "widget_type": "GRAPH", + "is_visible": "true", "metrics":[ { "name": "regionserver.Server.Append_num_ops", @@ -54,6 +55,7 @@ "display_name": "Files Local", "description": "This widget shows percentage of files local.", "widget_type": "NUMBER", + "is_visible": "true", "metrics":[ { "name": "regionserver.Server.percentFilesLocal", @@ -77,6 +79,7 @@ "widget_name": "NAMENODE_HEAP", "display_name": "NameNode Heap", "widget_type": "GAUGE", + "is_visible": "true", "description": "", "metrics":[ { http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/controllers/main/service/info/summary.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/service/info/summary.js b/ambari-web/app/controllers/main/service/info/summary.js index d1d1be8..1eec9d1 100644 --- a/ambari-web/app/controllers/main/service/info/summary.js +++ b/ambari-web/app/controllers/main/service/info/summary.js @@ -41,6 +41,13 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({ isPreviousRangerConfigsCallFailed: false, /** + * UI section name + */ + sectionName: function() { + return this.get('content.serviceName') + "_SUMMARY"; + }.property('content.serviceName'), + + /** * Ranger plugins data * @type {array} */ @@ -298,13 +305,46 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({ isWidgetsLoaded: false, /** - * @type Em.A + * @type {boolean} + */ + isWidgetLayoutsLoaded: false, + + /** + * @type {Em.A} */ widgets: function() { return App.Widget.find().filterProperty('serviceName', this.get('content.serviceName')); }.property('isWidgetsLoaded'), /** + * @type {Em.A} + */ + widgetLayouts: function() { + return App.WidgetLayout.find().filterProperty('serviceName', this.get('content.serviceName')); + }.property('isWidgetLayoutsLoaded'), + + /** + * load widget layouts across all users in CLUSTER scope + * @returns {$.ajax} + */ + loadWidgetLayouts: function() { + this.set('isWidgetLayoutsLoaded', false); + return App.ajax.send({ + name: 'widgets.layouts.get', + sender: this, + data: { + sectionName: this.get('sectionName') + }, + success: 'loadWidgetLayoutsSuccessCallback' + }); + }, + + loadWidgetLayoutsSuccessCallback: function(data) { + App.widgetLayoutMapper.map(data); + this.set('isWidgetLayoutsLoaded', true); + }, + + /** * load widgets defined by user * @returns {$.ajax} */ @@ -315,7 +355,7 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({ sender: this, data: { loginName: App.router.get('loginName'), - sectionName: this.get('content.serviceName') + "_SUMMARY" + sectionName: this.get('sectionName') }, success: 'loadWidgetsSuccessCallback' }); @@ -355,8 +395,38 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({ * @param {object|null} data */ loadStackWidgetsLayoutSuccessCallback: function (data) { - App.widgetMapper.map(data.artifact_data.layouts.findProperty('section_name', (this.get('content.serviceName') + "_SUMMARY")), this.get('content.serviceName')); + App.widgetMapper.map(data.artifact_data.layouts.findProperty('section_name', this.get('sectionName')), this.get('content.serviceName')); this.set('isWidgetsLoaded', true); + }, + + /** + * add widgets + */ + addWidgets: function (event) { + var widgets = event.context.filterProperty('selected'); + + }, + + /** + * delete widgets + */ + deleteWidgets: function (event) { + var widgets = event.context.filterProperty('selected'); + + }, + + /** + * save layout + */ + saveLayout: function () { + + }, + + /** + * create widget + */ + createWidget: function () { + } }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/mappers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js index 6939c0f..b96fc50 100644 --- a/ambari-web/app/mappers.js +++ b/ambari-web/app/mappers.js @@ -43,3 +43,4 @@ require('mappers/alert_groups_mapper'); require('mappers/alert_notification_mapper'); require('mappers/root_service_mapper'); require('mappers/widget_mapper'); +require('mappers/widget_layout_mapper'); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/mappers/widget_layout_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/widget_layout_mapper.js b/ambari-web/app/mappers/widget_layout_mapper.js new file mode 100644 index 0000000..d46099d --- /dev/null +++ b/ambari-web/app/mappers/widget_layout_mapper.js @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +App.widgetLayoutMapper = App.QuickDataMapper.create({ + model: App.WidgetLayout, + config: { + id: 'widget_layouts.layout_name', + layout_name: 'widget_layouts.layout_name', + section_name: 'widget_layouts.section_name', + scope: 'widget_layouts.scope', + user: 'Users.user_name' + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/mappers/widget_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/widget_mapper.js b/ambari-web/app/mappers/widget_mapper.js index 1df5003..c9b1aef 100644 --- a/ambari-web/app/mappers/widget_mapper.js +++ b/ambari-web/app/mappers/widget_mapper.js @@ -33,7 +33,8 @@ App.widgetMapper = App.QuickDataMapper.create({ properties: 'properties', metrics: 'metrics', values: 'values', - description: 'description' + description: 'description', + is_visible: 'is_visible' }, map: function (json, serviceName) { //TODO add service name to user layout API response http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 92c0a74..86093fc 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -2236,6 +2236,9 @@ Em.I18n.translations = { 'dashboard.button.switchShort': 'Switch', 'dashboard.button.reset': 'Reset all widgets to default ', 'dashboard.button.gangliaLink': 'View metrics in Ganglia', + 'dashboard.widgets.create': 'Create New Widget', + 'dashboard.widgets.layout.import': 'Import a layout', + 'dashboard.widgets.layout.save': 'Save a layout', 'dashboard.widgets.NameNodeHeap': 'NameNode Heap', 'dashboard.widgets.NameNodeCpu': 'NameNode CPU WIO', http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/mixins/common/widget_mixin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/widget_mixin.js b/ambari-web/app/mixins/common/widget_mixin.js index 7d1abfe..5ed262c 100644 --- a/ambari-web/app/mixins/common/widget_mixin.js +++ b/ambari-web/app/mixins/common/widget_mixin.js @@ -55,10 +55,26 @@ App.WidgetMixin = Ember.Mixin.create({ */ content: null, + beforeRender: function () { + this.loadMetrics(); + }, + + /** + * callback on metrics loaded + */ + onMetricsLoaded: function () { + var self = this; + this.set('isLoaded', true); + this.drawWidget(); + setTimeout(function() { + self.loadMetrics(); + }, App.contentUpdateInterval); + }, + /** * load metrics */ - beforeRender: function () { + loadMetrics: function () { var requestData = this.getRequestData(this.get('content.metrics')), request, requestCounter = 0, @@ -70,12 +86,12 @@ App.WidgetMixin = Ember.Mixin.create({ if (request.host_component_criteria) { this.getHostComponentMetrics(request).complete(function () { requestCounter--; - if (requestCounter === 0) self.set('isLoaded', true); + if (requestCounter === 0) self.onMetricsLoaded(); }); } else { this.getServiceComponentMetrics(request).complete(function () { requestCounter--; - if (requestCounter === 0) self.set('isLoaded', true); + if (requestCounter === 0) self.onMetricsLoaded(); }); } } @@ -111,7 +127,7 @@ App.WidgetMixin = Ember.Mixin.create({ this.get('content.values').forEach(function (value) { var computeExpression = this.computeExpression(this.extractExpressions(value), metrics); value.computedValue = value.value.replace(this.get('EXPRESSION_REGEX'), function (match) { - return (computeExpression[match]) ? computeExpression[match] + (displayUnit || "") : Em.I18n.t('common.na'); + return (!Em.isNone(computeExpression[match])) ? computeExpression[match] + (displayUnit || "") : Em.I18n.t('common.na'); }); }, this); }, @@ -194,7 +210,7 @@ App.WidgetMixin = Ember.Mixin.create({ var metrics = []; this.get('content.metrics').forEach(function (_metric) { - if (Em.get(data, _metric.widget_id.replace(/\//g, '.'))) { + if (!Em.isNone(Em.get(data, _metric.widget_id.replace(/\//g, '.')))) { _metric.data = Em.get(data, _metric.widget_id.replace(/\//g, '.')); this.get('metrics').pushObject(_metric); } http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/models.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models.js b/ambari-web/app/models.js index 6f5da37..e9de30f 100644 --- a/ambari-web/app/models.js +++ b/ambari-web/app/models.js @@ -68,4 +68,5 @@ require('models/configs/config_property'); require('models/configs/tab'); require('models/configs/section'); require('models/configs/sub_section'); -require('models/widget'); \ No newline at end of file +require('models/widget'); +require('models/widget_layout'); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/models/widget.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/widget.js b/ambari-web/app/models/widget.js index b093a53..e00cd05 100644 --- a/ambari-web/app/models/widget.js +++ b/ambari-web/app/models/widget.js @@ -27,7 +27,6 @@ App.Widget = DS.Model.extend({ * - HEATMAP * - GRAPH (Line graph and stack graph) * - NUMBER (e.g., â1 msâ for RPC latency) - * - x / y (e.g., â2 / 3â DataNodes live) * - LINKS * - TEMPLATE */ @@ -42,6 +41,7 @@ App.Widget = DS.Model.extend({ expression: DS.attr('array'), metrics: DS.attr('array'), values: DS.attr('array'), + isVisible: DS.attr('boolean'), /** * @type {number} http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/models/widget_layout.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/widget_layout.js b/ambari-web/app/models/widget_layout.js index b7cf9bb..2c29670 100644 --- a/ambari-web/app/models/widget_layout.js +++ b/ambari-web/app/models/widget_layout.js @@ -20,8 +20,10 @@ var App = require('app'); App.WidgetLayout = DS.Model.extend({ layoutName: DS.attr('string'), - sectionName:DS.attr('string'), - widgetLayoutInfo: DS.attr('string') + sectionName: DS.attr('string'), + widgetLayoutInfo: DS.attr('string'), + scope: DS.attr('string'), + user: DS.attr('string') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/styles/enhanced_service_dashboard.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/enhanced_service_dashboard.less b/ambari-web/app/styles/enhanced_service_dashboard.less index 8555f44..4d74488 100644 --- a/ambari-web/app/styles/enhanced_service_dashboard.less +++ b/ambari-web/app/styles/enhanced_service_dashboard.less @@ -25,8 +25,53 @@ .icon-plus { font-size: 70px; color: #ddd; - position: center; } } + .actions .dropdown-menu { + min-width: 270px; + label.checkbox { + padding: 0 20px 0 38px; + margin-bottom: 0; + margin-top: 5px; + } + li.btn-row { + padding: 5px 20px 10px 20px; + } + a.action { + border-bottom: 1px solid #ddd + } + } +} + +#widget_layout { + .widget { + .spinner { + margin: 55px auto; + } + .title { + padding: 5px 0 0 5px; + height: 25px; + font-weight: bold; + text-align: left; + } + .content { + text-align: center; + color: #5ab400; + padding-top: 35px; + font-weight: bold; + font-size: 35px; + } + .template-widget { + height: 150px; + width: 90%; + } + .gauge-widget { + height: 150px; + width: 90%; + .content { + padding-top: 5px; + } + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/styles/widget_layout.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/widget_layout.less b/ambari-web/app/styles/widget_layout.less deleted file mode 100644 index 8b4b94c..0000000 --- a/ambari-web/app/styles/widget_layout.less +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#widget_layout { - .widget { - .title { - padding: 5px 0 0 5px; - height: 25px; - font-weight: bold; - text-align: left; - } - .content { - text-align: center; - color: #5ab400; - padding-top: 35px; - font-weight: bold; - font-size: 35px; - } - .template-widget { - height: 150px; - width: 90%; - } - .gauge-widget { - height: 150px; - width: 90%; - .content { - padding-top: 5px; - } - } - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/templates/common/widget/gauge_widget.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/widget/gauge_widget.hbs b/ambari-web/app/templates/common/widget/gauge_widget.hbs index 03a975f..11e3565 100644 --- a/ambari-web/app/templates/common/widget/gauge_widget.hbs +++ b/ambari-web/app/templates/common/widget/gauge_widget.hbs @@ -17,6 +17,10 @@ }} <div class="gauge-widget thumbnail"> - <div class="caption title">{{view.title}}</div> - <div class="content"> {{view view.chartView}}</div> + {{#if view.isLoaded}} + <div class="caption title">{{view.title}}</div> + <div class="content"> {{view view.chartView}}</div> + {{else}} + <div class="spinner"></div> + {{/if}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/templates/common/widget/template_widget.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/widget/template_widget.hbs b/ambari-web/app/templates/common/widget/template_widget.hbs index fda71ea..02f7425 100644 --- a/ambari-web/app/templates/common/widget/template_widget.hbs +++ b/ambari-web/app/templates/common/widget/template_widget.hbs @@ -17,6 +17,10 @@ }} <div class="template-widget thumbnail"> - <div class="caption title">{{view.title}}</div> - <div class="content"> {{view.value}}</div> + {{#if view.isLoaded}} + <div class="caption title">{{view.title}}</div> + <div class="content"> {{view.value}}</div> + {{else}} + <div class="spinner"></div> + {{/if}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/templates/main/service/info/summary.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/service/info/summary.hbs b/ambari-web/app/templates/main/service/info/summary.hbs index e87ca6b..92f7cbd 100644 --- a/ambari-web/app/templates/main/service/info/summary.hbs +++ b/ambari-web/app/templates/main/service/info/summary.hbs @@ -89,10 +89,50 @@ </ul> </div> {{#if App.supports.customizedWidgets}} - <div class="btn-group pull-right"> + <div class="btn-group pull-right actions"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> {{t common.actions}} <span class="caret"></span> </button> + <ul class="dropdown-menu"> + {{#each option in view.widgetActions}} + <li {{bindAttr class="option.layouts:dropdown-submenu"}}> + {{#if option.isAction}} + <a href="javascript:void(0);" class="action" {{action doWidgetAction option.action target="view"}}> + <i {{bindAttr class="option.class"}}></i> + {{option.label}} + </a> + {{#if option.layouts}} + <ul class="dropdown-menu"> + {{#each layout in option.layouts}} + <li> + <a href="javascript:void(0);"> + {{layout.layoutName}} + </a> + </li> + {{/each}} + </ul> + {{/if}} + {{else}} + <label class="checkbox"> + {{view Em.Checkbox checkedBinding="option.selected"}} + {{option.label}} + </label> + {{/if}} + </li> + {{/each}} + <li> + <a href="javascript:void(0);"> + {{t hostPopup.serviceInfo.showMore}} + </a> + </li> + <li class="btn-row"> + <div class="row-fluid"> + <button class="btn span4">{{t common.cancel}}</button> + <button class="btn btn-danger span4" {{action deleteWidgets view.widgetActions target="controller"}}>{{t common.delete}}</button> + <button class="btn btn-primary span4" {{action addWidgets view.widgetActions target="controller"}}>{{t common.add}}</button> + </div> + </li> + </ul> </div> {{/if}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 1118d37..7b7c6fb 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -2413,6 +2413,11 @@ var urls = { mock: '/data/widget_layouts/HBASE/empty_user_layout.json' }, + 'widgets.layouts.get': { + real: '/users?widget_layouts/section_name={sectionName}&widget_layouts/scope=CLUSTER', + mock: '/data/widget_layouts/HBASE/layouts.json' + }, + 'widgets.serviceComponent.metrics.get': { real: '/clusters/{clusterName}/services/{serviceName}/components/{componentName}?fields={widgetIds}', mock: '/data/metrics/{serviceName}/Append_num_ops_&_Delete_num_ops.json' http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/views/common/widget/gauge_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/widget/gauge_widget_view.js b/ambari-web/app/views/common/widget/gauge_widget_view.js index 0964e11..7a31d14 100644 --- a/ambari-web/app/views/common/widget/gauge_widget_view.js +++ b/ambari-web/app/views/common/widget/gauge_widget_view.js @@ -43,7 +43,7 @@ App.GaugeWidgetView = Em.View.extend(App.WidgetMixin, { this.set('title', this.get('content.values')[0].name); this.set('value', this.get('content.values')[0].computedValue); } - }.observes('isLoaded'), + }, chartView: App.ChartPieView.extend({ stroke: '#D6DDDF', //light grey @@ -76,7 +76,7 @@ App.GaugeWidgetView = Em.View.extend(App.WidgetMixin, { data: function () { var data = parseFloat(this.get('parentView.value')) * this.get('FACTOR'); - if (isNaN(data)) return [this.get('MAX_VALUE'), 0]; + if (isNaN(data)) return [0, this.get('MAX_VALUE')]; return [data, this.get('MAX_VALUE') - data]; }.property('parentView.value'), http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/views/common/widget/graph_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/widget/graph_widget_view.js b/ambari-web/app/views/common/widget/graph_widget_view.js index 2e4f0d9..9d2e4f5 100644 --- a/ambari-web/app/views/common/widget/graph_widget_view.js +++ b/ambari-web/app/views/common/widget/graph_widget_view.js @@ -69,7 +69,7 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend(App.WidgetMixin, { if (this.get('isLoaded')) { this._refreshGraph(this.calculateValues()) } - }.observes('isLoaded'), + }, /** * calculate series datasets for graph widgets http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/views/common/widget/template_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/widget/template_widget_view.js b/ambari-web/app/views/common/widget/template_widget_view.js index 9b9d844..572e4fb 100644 --- a/ambari-web/app/views/common/widget/template_widget_view.js +++ b/ambari-web/app/views/common/widget/template_widget_view.js @@ -43,5 +43,5 @@ App.TemplateWidgetView = Em.View.extend(App.WidgetMixin, { this.set('value', this.get('content.values')[0].computedValue); this.set('title', this.get('content.values')[0].name); } - }.observes('isLoaded') + } }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/app/views/main/service/info/summary.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js index 9e108bf..f4e123d 100644 --- a/ambari-web/app/views/main/service/info/summary.js +++ b/ambari-web/app/views/main/service/info/summary.js @@ -365,6 +365,58 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, { this.set('currentTimeRangeIndex', 0); } }, + /** + * list of static actions of widget + * @type {Array} + */ + staticWidgetActions: [ + Em.Object.create({ + label: Em.I18n.t('dashboard.widgets.layout.save'), + class: 'icon-download-alt', + action: 'saveLayout', + isAction: true + }), + Em.Object.create({ + label: Em.I18n.t('dashboard.widgets.layout.import'), + class: 'icon-file', + isAction: true, + layouts: App.WidgetLayout.find() + }), + Em.Object.create({ + label: Em.I18n.t('dashboard.widgets.create'), + class: 'icon-plus', + action: 'createWidget', + isAction: true + }) + ], + + /** + * @type {Array} + */ + widgetActions: function() { + var options = []; + + options.pushObjects(this.get('staticWidgetActions')); + this.get('controller.widgets').forEach(function (widget) { + options.push(Em.Object.create({ + label: widget.get('displayName'), + isVisible: widget.get('isVisible'), + selected: true + })); + }, this); + + return options; + }.property('controller.widgets.length'), + + /** + * call action function defined in controller + * @param event + */ + doWidgetAction: function(event) { + if($.isFunction(this.get('controller')[event.context])) { + this.get('controller')[event.context].apply(this.get('controller')); + } + }, /** * time range options for service metrics, a dropdown will list all options @@ -478,6 +530,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, { var stackService = App.StackService.find().findProperty('serviceName', serviceName); if (stackService.get('isServiceWithWidgets')) { this.get('controller').loadWidgets(); + this.get('controller').loadWidgetLayouts(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/12598cff/ambari-web/test/mixins/common/widget_mixin_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mixins/common/widget_mixin_test.js b/ambari-web/test/mixins/common/widget_mixin_test.js index 2ee9edd..edb5359 100644 --- a/ambari-web/test/mixins/common/widget_mixin_test.js +++ b/ambari-web/test/mixins/common/widget_mixin_test.js @@ -21,7 +21,7 @@ var App = require('app'); describe('App.WidgetMixin', function() { var mixinClass = Em.Object.extend(App.WidgetMixin, {metrics: [], content: {}}); - describe('#beforeRender()', function () { + describe('#loadMetrics()', function () { var mixinObject = mixinClass.create(); beforeEach(function () { this.mock = sinon.stub(mixinObject, 'getRequestData'); @@ -31,27 +31,29 @@ describe('App.WidgetMixin', function() { sinon.stub(mixinObject, 'getServiceComponentMetrics').returns({complete: function(callback){ callback(); }}); + sinon.stub(mixinObject, 'onMetricsLoaded'); }); afterEach(function () { this.mock.restore(); mixinObject.getHostComponentMetrics.restore(); mixinObject.getServiceComponentMetrics.restore(); + mixinObject.onMetricsLoaded.restore(); }); it('has host_component_criteria', function () { this.mock.returns({'key1': {host_component_criteria: 'criteria'}}); mixinObject.set('isLoaded', false); - mixinObject.beforeRender(); + mixinObject.loadMetrics(); expect(mixinObject.getHostComponentMetrics.calledWith({host_component_criteria: 'criteria'})).to.be.true; - expect(mixinObject.get('isLoaded')).to.be.true; + expect(mixinObject.onMetricsLoaded.calledOnce).to.be.true; }); it('host_component_criteria is absent', function () { this.mock.returns({'key1': {}}); mixinObject.set('isLoaded', false); - mixinObject.beforeRender(); + mixinObject.loadMetrics(); expect(mixinObject.getServiceComponentMetrics.calledWith({})).to.be.true; - expect(mixinObject.get('isLoaded')).to.be.true; + expect(mixinObject.onMetricsLoaded.calledOnce).to.be.true; }); });
