You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2017/10/09 12:06:04 UTC
[2/2] ambari git commit: AMBARI-22168 Move service metrics to
separate tab. (atkach)
AMBARI-22168 Move service metrics to separate tab. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6eb273e1
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6eb273e1
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6eb273e1
Branch: refs/heads/trunk
Commit: 6eb273e19a81773c27f235631c54a3e142277f08
Parents: e83c86d
Author: Andrii Tkach <at...@apache.org>
Authored: Mon Oct 9 14:11:36 2017 +0300
Committer: Andrii Tkach <at...@apache.org>
Committed: Mon Oct 9 15:01:28 2017 +0300
----------------------------------------------------------------------
ambari-web/app/assets/test/tests.js | 2 +
ambari-web/app/controllers.js | 1 +
.../app/controllers/main/service/info/metric.js | 468 +++++++++++++++++++
.../controllers/main/service/info/summary.js | 449 +-----------------
.../service/widgets/create/wizard_controller.js | 2 +-
ambari-web/app/messages.js | 1 +
.../app/styles/enhanced_service_dashboard.less | 26 +-
.../app/templates/main/service/info/metrics.hbs | 104 +++++
.../app/templates/main/service/info/summary.hbs | 84 ----
ambari-web/app/templates/main/service/item.hbs | 5 +-
ambari-web/app/views.js | 1 +
ambari-web/app/views/main/service/info/menu.js | 7 +
.../app/views/main/service/info/metrics_view.js | 290 ++++++++++++
.../app/views/main/service/info/summary.js | 315 ++-----------
ambari-web/app/views/main/service/item.js | 6 +
.../main/service/info/metric_test.js | 110 +++++
.../main/service/info/summary_test.js | 76 ---
.../main/service/info/metrics_view_test.js | 334 +++++++++++++
.../views/main/service/info/summary_test.js | 281 +----------
19 files changed, 1400 insertions(+), 1162 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 03b4657..7c636d4 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -125,6 +125,7 @@ var files = [
'test/controllers/main/service/item_test',
'test/controllers/main/service/info/config_test',
'test/controllers/main/service/info/summary_test',
+ 'test/controllers/main/service/info/metric_test',
'test/controllers/main/service_test',
'test/controllers/main/admin_test',
'test/controllers/main/views_controller_test',
@@ -340,6 +341,7 @@ var files = [
'test/views/main/service/service_test',
'test/views/main/service/info/config_test',
'test/views/main/service/info/summary_test',
+ 'test/views/main/service/info/metrics_view_test',
'test/views/main/service/info/menu_test',
'test/views/main/service/info/component_list_view_test',
'test/views/main/service/info/metrics/ambari_metrics/regionserver_base_test',
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 81e5eb7..f7d77be 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -142,6 +142,7 @@ require('controllers/main/charts');
require('controllers/main/charts/heatmap_metrics/heatmap_metric');
require('controllers/main/charts/heatmap');
require('controllers/main/service/info/heatmap');
+require('controllers/main/service/info/metric');
require('controllers/main/views_controller');
require('controllers/main/views/details_controller');
require('controllers/wizard/step0_controller');
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/controllers/main/service/info/metric.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/metric.js b/ambari-web/app/controllers/main/service/info/metric.js
new file mode 100644
index 0000000..9dfc32c
--- /dev/null
+++ b/ambari-web/app/controllers/main/service/info/metric.js
@@ -0,0 +1,468 @@
+/**
+ * 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.MainServiceInfoMetricsController = Em.Controller.extend(App.WidgetSectionMixin, {
+ name: 'mainServiceInfoMetricsController',
+
+ layoutNameSuffix: "_dashboard",
+
+ sectionNameSuffix: "_SUMMARY",
+
+ /**
+ * Some widget has type `GRAPH`
+ *
+ * @type {boolean}
+ */
+ someWidgetGraphExists: Em.computed.someBy('widgets', 'widgetType', 'GRAPH'),
+
+ /**
+ * @type {boolean}
+ */
+ showTimeRangeControl: Em.computed.or('!isServiceWithEnhancedWidgets', 'someWidgetGraphExists'),
+
+ /**
+ * @type {boolean}
+ */
+ isWidgetLayoutsLoaded: false,
+
+ /**
+ * @type {boolean}
+ */
+ isAllSharedWidgetsLoaded: false,
+
+ /**
+ * @type {boolean}
+ */
+ isMineWidgetsLoaded: false,
+
+ /**
+ * 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 all shared widgets to show on widget browser
+ * @returns {$.ajax}
+ */
+ loadAllSharedWidgets: function () {
+ this.set('isAllSharedWidgetsLoaded', false);
+ return App.ajax.send({
+ name: 'widgets.all.shared.get',
+ sender: this,
+ success: 'loadAllSharedWidgetsSuccessCallback'
+ });
+ },
+
+ /**
+ * success callback of <code>loadAllSharedWidgets</code>
+ * @param {object|null} data
+ */
+ loadAllSharedWidgetsSuccessCallback: function (data) {
+ var widgetIds = this.get('widgets').mapProperty('id');
+ if (data.items[0] && data.items.length) {
+ this.set("allSharedWidgets",
+ data.items.filter(function (widget) {
+ return widget.WidgetInfo.widget_type != "HEATMAP";
+ }).map(function (widget) {
+ var widgetType = widget.WidgetInfo.widget_type;
+ var widgetName = widget.WidgetInfo.widget_name;
+ var widgetId = widget.WidgetInfo.id;
+ return Em.Object.create({
+ id: widgetId,
+ widgetName: widgetName,
+ description: widget.WidgetInfo.description,
+ widgetType: widgetType,
+ iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
+ serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
+ added: widgetIds.contains(widgetId),
+ isShared: widget.WidgetInfo.scope == "CLUSTER"
+ });
+ })
+ );
+ }
+ this.set('isAllSharedWidgetsLoaded', true);
+ },
+
+ allSharedWidgets: [],
+ mineWidgets: [],
+
+ /**
+ * load all mine widgets of current user to show on widget browser
+ * @returns {$.ajax}
+ */
+ loadMineWidgets: function () {
+ this.set('isMineWidgetsLoaded', false);
+ return App.ajax.send({
+ name: 'widgets.all.mine.get',
+ sender: this,
+ data: {
+ loginName: App.router.get('loginName')
+ },
+ success: 'loadMineWidgetsSuccessCallback'
+ });
+ },
+
+ /**
+ * success callback of <code>loadMineWidgets</code>
+ * @param {object|null} data
+ */
+ loadMineWidgetsSuccessCallback: function (data) {
+ var widgetIds = this.get('widgets').mapProperty('id');
+ if (data.items[0] && data.items.length) {
+ this.set("mineWidgets",
+ data.items.filter(function (widget) {
+ return widget.WidgetInfo.widget_type != "HEATMAP";
+ }).map(function (widget) {
+ var widgetType = widget.WidgetInfo.widget_type;
+ var widgetName = widget.WidgetInfo.widget_name;
+ var widgetId = widget.WidgetInfo.id;
+ return Em.Object.create({
+ id: widget.WidgetInfo.id,
+ widgetName: widgetName,
+ description: widget.WidgetInfo.description,
+ widgetType: widgetType,
+ iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
+ serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
+ added: widgetIds.contains(widgetId),
+ isShared: widget.WidgetInfo.scope == "CLUSTER"
+ });
+ })
+ );
+ } else {
+ this.set("mineWidgets", []);
+ }
+ this.set('isMineWidgetsLoaded', true);
+ },
+
+ /**
+ * add widgets, on click handler for "Add"
+ */
+ addWidget: function (event) {
+ var widgetToAdd = event.context;
+ var activeLayout = this.get('activeWidgetLayout');
+ var widgetIds = activeLayout.get('widgets').map(function(widget) {
+ return {
+ "id": widget.get("id")
+ }
+ });
+ widgetIds.pushObject({
+ "id": widgetToAdd.id
+ });
+ var data = {
+ "WidgetLayoutInfo": {
+ "display_name": activeLayout.get("displayName"),
+ "id": activeLayout.get("id"),
+ "layout_name": activeLayout.get("layoutName"),
+ "scope": activeLayout.get("scope"),
+ "section_name": activeLayout.get("sectionName"),
+ "widgets": widgetIds
+ }
+ };
+
+ widgetToAdd.set('added', !widgetToAdd.added);
+ return App.ajax.send({
+ name: 'widget.layout.edit',
+ sender: this,
+ data: {
+ layoutId: activeLayout.get("id"),
+ data: data
+ },
+ success: 'updateActiveLayout'
+ });
+ },
+
+ /**
+ * hide widgets, on click handler for "Added"
+ */
+ hideWidget: function (event) {
+ var widgetToHide = event.context;
+ var activeLayout = this.get('activeWidgetLayout');
+ var widgetIds = activeLayout.get('widgets').map(function (widget) {
+ return {
+ "id": widget.get("id")
+ }
+ });
+ var data = {
+ "WidgetLayoutInfo": {
+ "display_name": activeLayout.get("displayName"),
+ "id": activeLayout.get("id"),
+ "layout_name": activeLayout.get("layoutName"),
+ "scope": activeLayout.get("scope"),
+ "section_name": activeLayout.get("sectionName"),
+ "widgets": widgetIds.filter(function (widget) {
+ return widget.id !== widgetToHide.id;
+ })
+ }
+ };
+
+ widgetToHide.set('added', !widgetToHide.added);
+ return App.ajax.send({
+ name: 'widget.layout.edit',
+ sender: this,
+ data: {
+ layoutId: activeLayout.get("id"),
+ data: data
+ },
+ success: 'hideWidgetSuccessCallback'
+ });
+
+ },
+
+ /**
+ * @param {object|null} data
+ * @param {object} opt
+ * @param {object} params
+ */
+ hideWidgetSuccessCallback: function (data, opt, params) {
+ params.data.WidgetLayoutInfo.widgets = params.data.WidgetLayoutInfo.widgets.map(function (widget) {
+ return {
+ WidgetInfo: {
+ id: widget.id
+ }
+ }
+ });
+ App.widgetLayoutMapper.map({items: [params.data]});
+ this.propertyDidChange('widgets');
+ },
+
+ /**
+ * update current active widget layout
+ */
+ updateActiveLayout: function () {
+ this.getActiveWidgetLayout();
+ },
+
+ /**
+ * delete widgets, on click handler for "Delete"
+ */
+ deleteWidget: function (event) {
+ var widget = event.context;
+ var self = this;
+ var confirmMsg = widget.get('isShared') ? Em.I18n.t('dashboard.widgets.browser.action.delete.shared.bodyMsg').format(widget.widgetName) : Em.I18n.t('dashboard.widgets.browser.action.delete.mine.bodyMsg').format(widget.widgetName);
+ var bodyMessage = Em.Object.create({
+ confirmMsg: confirmMsg,
+ confirmButton: Em.I18n.t('dashboard.widgets.browser.action.delete.btnMsg')
+ });
+ return App.showConfirmationFeedBackPopup(function (query) {
+ return App.ajax.send({
+ name: 'widget.action.delete',
+ sender: self,
+ data: {
+ id: widget.id
+ },
+ success: 'updateWidgetBrowser'
+ });
+
+ }, bodyMessage);
+ },
+
+ /**
+ * update widget browser content after deleted some widget
+ */
+ updateWidgetBrowser: function () {
+ this.loadAllSharedWidgets();
+ this.loadMineWidgets();
+ },
+
+ /**
+ * Share widgets, on click handler for "Share"
+ */
+ shareWidget: function (event) {
+ var widget = event.context;
+ var self = this;
+ var bodyMessage = Em.Object.create({
+ confirmMsg: Em.I18n.t('dashboard.widgets.browser.action.share.confirmation'),
+ confirmButton: Em.I18n.t('dashboard.widgets.browser.action.share')
+ });
+ return App.showConfirmationFeedBackPopup(function (query) {
+ return App.ajax.send({
+ name: 'widgets.wizard.edit',
+ sender: self,
+ data: {
+ data: {
+ "WidgetInfo": {
+ "widget_name": widget.get("widgetName"),
+ "scope": "CLUSTER"
+ }
+ },
+ widgetId: widget.get("id")
+ },
+ success: 'updateWidgetBrowser'
+ });
+ }, bodyMessage);
+ },
+
+ /**
+ * create widget
+ */
+ createWidget: function () {
+ App.router.send('createServiceWidget', Em.Object.create({
+ layout: this.get('activeWidgetLayout'),
+ serviceName: this.get('content.serviceName')
+ }));
+ },
+
+ /**
+ * edit widget
+ * @param {App.Widget} content
+ */
+ editWidget: function (content) {
+ content.set('serviceName', this.get('content.serviceName'));
+ App.router.send('editServiceWidget', content);
+ },
+
+ /**
+ * launch Widgets Browser popup
+ * @method showPopup
+ * @return {App.ModalPopup}
+ */
+ goToWidgetsBrowser: function () {
+ var self = this;
+
+ return App.ModalPopup.show({
+ header: Em.I18n.t('dashboard.widgets.browser.header'),
+
+ classNames: ['common-modal-wrapper', 'widgets-browser-popup'],
+ modalDialogClasses: ['modal-lg'],
+ onPrimary: function () {
+ this.hide();
+ self.set('isAllSharedWidgetsLoaded', false);
+ self.set('allSharedWidgets', []);
+ self.set('isMineWidgetsLoaded', false);
+ self.set('mineWidgets', []);
+ },
+ autoHeight: false,
+ isHideBodyScroll: false,
+ footerClass: Ember.View.extend({
+ templateName: require('templates/common/modal_popups/widget_browser_footer'),
+ isShowMineOnly: false,
+ onPrimary: function() {
+ this.get('parentView').onPrimary();
+ }
+ }),
+ isShowMineOnly: false,
+ bodyClass: Ember.View.extend({
+ templateName: require('templates/common/modal_popups/widget_browser_popup'),
+ controller: self,
+ willInsertElement: function () {
+ this.get('controller').loadAllSharedWidgets();
+ this.get('controller').loadMineWidgets();
+ },
+
+ isLoaded: Em.computed.and('controller.isAllSharedWidgetsLoaded', 'controller.isMineWidgetsLoaded'),
+
+ isWidgetEmptyList: Em.computed.empty('filteredContent'),
+
+ activeService: '',
+ activeStatus: '',
+
+ content: function () {
+ if (this.get('parentView.isShowMineOnly')) {
+ return this.get('controller.mineWidgets');
+ } else {
+ // merge my widgets and all shared widgets, no duplicated is allowed
+ var content = [];
+ var widgetMap = {};
+ var allWidgets = this.get('controller.allSharedWidgets').concat(this.get('controller.mineWidgets'));
+ allWidgets.forEach(function(widget) {
+ if (!widgetMap[widget.get("id")]) {
+ content.pushObject(widget);
+ widgetMap[widget.get("id")] = true;
+ }
+ });
+ return content;
+ }
+ }.property('controller.allSharedWidgets.length', 'controller.isAllSharedWidgetsLoaded',
+ 'controller.mineWidgets.length', 'controller.isMineWidgetsLoaded', 'parentView.isShowMineOnly'),
+
+ /**
+ * displaying content filtered by service name and status.
+ */
+ filteredContent: function () {
+ var activeService = this.get('activeService') ? this.get('activeService') : this.get('controller.content.serviceName');
+ var result = [];
+ this.get('content').forEach(function (widget) {
+ if (widget.get('serviceName').indexOf(activeService) >= 0) {
+ result.pushObject(widget);
+ }
+ });
+ return result;
+ }.property('content', 'activeService', 'activeStatus'),
+
+ /**
+ * service name filter
+ */
+ services: function () {
+ var view = this;
+ var services = App.Service.find().filter(function(item){
+ var stackService = App.StackService.find().findProperty('serviceName', item.get('serviceName'));
+ return stackService.get('isServiceWithWidgets');
+ });
+ return services.map(function (service) {
+ return Em.Object.create({
+ value: service.get('serviceName'),
+ label: service.get('displayName'),
+ isActive: function () {
+ var activeService = view.get('activeService') ? view.get('activeService') : view.get('controller.content.serviceName');
+ return this.get('value') == activeService;
+ }.property('value', 'view.activeService')
+ })
+ });
+ }.property('activeService'),
+
+ filterByService: function (event) {
+ this.set('activeService', event.context);
+ },
+
+ createWidget: function () {
+ this.get('parentView').onPrimary();
+ this.get('controller').createWidget();
+ },
+
+ ensureTooltip: function () {
+ Em.run.later(this, function () {
+ App.tooltip($("[rel='shared-icon-tooltip']"));
+ }, 1000);
+ }.observes('activeService', 'parentView.isShowMineOnly'),
+
+ didInsertElement: function () {
+ this.ensureTooltip();
+ }
+ })
+ });
+ }
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/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 d696334..3d7483a 100644
--- a/ambari-web/app/controllers/main/service/info/summary.js
+++ b/ambari-web/app/controllers/main/service/info/summary.js
@@ -17,7 +17,7 @@
var App = require('app');
-App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMixin, {
+App.MainServiceInfoSummaryController = Em.Controller.extend({
name: 'mainServiceInfoSummaryController',
selectedFlumeAgent: null,
@@ -40,10 +40,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMix
*/
isPreviousRangerConfigsCallFailed: false,
- layoutNameSuffix: "_dashboard",
-
- sectionNameSuffix: "_SUMMARY",
-
/**
* HiveServer2 JDBC connection endpoint data
* @type {array}
@@ -112,18 +108,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMix
],
/**
- * Some widget has type `GRAPH`
- *
- * @type {boolean}
- */
- someWidgetGraphExists: Em.computed.someBy('widgets', 'widgetType', 'GRAPH'),
-
- /**
- * @type {boolean}
- */
- showTimeRangeControl: Em.computed.or('!isServiceWithEnhancedWidgets', 'someWidgetGraphExists'),
-
- /**
* Set initial Ranger plugins data
* @method setRangerPlugins
*/
@@ -425,437 +409,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMix
});
},
-
- /**
- * @type {boolean}
- */
- isWidgetLayoutsLoaded: false,
-
- /**
- * @type {boolean}
- */
- isAllSharedWidgetsLoaded: false,
-
- /**
- * @type {boolean}
- */
- isMineWidgetsLoaded: false,
-
-
- /**
- * 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 all shared widgets to show on widget browser
- * @returns {$.ajax}
- */
- loadAllSharedWidgets: function () {
- this.set('isAllSharedWidgetsLoaded', false);
- return App.ajax.send({
- name: 'widgets.all.shared.get',
- sender: this,
- success: 'loadAllSharedWidgetsSuccessCallback'
- });
- },
-
- /**
- * success callback of <code>loadAllSharedWidgets</code>
- * @param {object|null} data
- */
- loadAllSharedWidgetsSuccessCallback: function (data) {
- var widgetIds = this.get('widgets').mapProperty('id');
- if (data.items[0] && data.items.length) {
- this.set("allSharedWidgets",
- data.items.filter(function (widget) {
- return widget.WidgetInfo.widget_type != "HEATMAP";
- }).map(function (widget) {
- var widgetType = widget.WidgetInfo.widget_type;
- var widgetName = widget.WidgetInfo.widget_name;
- var widgetId = widget.WidgetInfo.id;
- return Em.Object.create({
- id: widgetId,
- widgetName: widgetName,
- description: widget.WidgetInfo.description,
- widgetType: widgetType,
- iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
- serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
- added: widgetIds.contains(widgetId),
- isShared: widget.WidgetInfo.scope == "CLUSTER"
- });
- })
- );
- }
- this.set('isAllSharedWidgetsLoaded', true);
- },
-
- allSharedWidgets: [],
- mineWidgets: [],
-
- /**
- * load all mine widgets of current user to show on widget browser
- * @returns {$.ajax}
- */
- loadMineWidgets: function () {
- this.set('isMineWidgetsLoaded', false);
- return App.ajax.send({
- name: 'widgets.all.mine.get',
- sender: this,
- data: {
- loginName: App.router.get('loginName')
- },
- success: 'loadMineWidgetsSuccessCallback'
- });
- },
-
- /**
- * success callback of <code>loadMineWidgets</code>
- * @param {object|null} data
- */
- loadMineWidgetsSuccessCallback: function (data) {
- var widgetIds = this.get('widgets').mapProperty('id');
- if (data.items[0] && data.items.length) {
- this.set("mineWidgets",
- data.items.filter(function (widget) {
- return widget.WidgetInfo.widget_type != "HEATMAP";
- }).map(function (widget) {
- var widgetType = widget.WidgetInfo.widget_type;
- var widgetName = widget.WidgetInfo.widget_name;
- var widgetId = widget.WidgetInfo.id;
- return Em.Object.create({
- id: widget.WidgetInfo.id,
- widgetName: widgetName,
- description: widget.WidgetInfo.description,
- widgetType: widgetType,
- iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
- serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
- added: widgetIds.contains(widgetId),
- isShared: widget.WidgetInfo.scope == "CLUSTER"
- });
- })
- );
- } else {
- this.set("mineWidgets", []);
- }
- this.set('isMineWidgetsLoaded', true);
- },
-
- /**
- * add widgets, on click handler for "Add"
- */
- addWidget: function (event) {
- var widgetToAdd = event.context;
- var activeLayout = this.get('activeWidgetLayout');
- var widgetIds = activeLayout.get('widgets').map(function(widget) {
- return {
- "id": widget.get("id")
- }
- });
- widgetIds.pushObject({
- "id": widgetToAdd.id
- });
- var data = {
- "WidgetLayoutInfo": {
- "display_name": activeLayout.get("displayName"),
- "id": activeLayout.get("id"),
- "layout_name": activeLayout.get("layoutName"),
- "scope": activeLayout.get("scope"),
- "section_name": activeLayout.get("sectionName"),
- "widgets": widgetIds
- }
- };
-
- widgetToAdd.set('added', !widgetToAdd.added);
- return App.ajax.send({
- name: 'widget.layout.edit',
- sender: this,
- data: {
- layoutId: activeLayout.get("id"),
- data: data
- },
- success: 'updateActiveLayout'
- });
- },
-
- /**
- * hide widgets, on click handler for "Added"
- */
- hideWidget: function (event) {
- var widgetToHide = event.context;
- var activeLayout = this.get('activeWidgetLayout');
- var widgetIds = activeLayout.get('widgets').map(function (widget) {
- return {
- "id": widget.get("id")
- }
- });
- var data = {
- "WidgetLayoutInfo": {
- "display_name": activeLayout.get("displayName"),
- "id": activeLayout.get("id"),
- "layout_name": activeLayout.get("layoutName"),
- "scope": activeLayout.get("scope"),
- "section_name": activeLayout.get("sectionName"),
- "widgets": widgetIds.filter(function (widget) {
- return widget.id !== widgetToHide.id;
- })
- }
- };
-
- widgetToHide.set('added', !widgetToHide.added);
- return App.ajax.send({
- name: 'widget.layout.edit',
- sender: this,
- data: {
- layoutId: activeLayout.get("id"),
- data: data
- },
- success: 'hideWidgetSuccessCallback'
- });
-
- },
-
- /**
- * @param {object|null} data
- * @param {object} opt
- * @param {object} params
- */
- hideWidgetSuccessCallback: function (data, opt, params) {
- params.data.WidgetLayoutInfo.widgets = params.data.WidgetLayoutInfo.widgets.map(function (widget) {
- return {
- WidgetInfo: {
- id: widget.id
- }
- }
- });
- App.widgetLayoutMapper.map({items: [params.data]});
- this.propertyDidChange('widgets');
- },
-
- /**
- * update current active widget layout
- */
- updateActiveLayout: function () {
- this.getActiveWidgetLayout();
- },
-
- /**
- * delete widgets, on click handler for "Delete"
- */
- deleteWidget: function (event) {
- var widget = event.context;
- var self = this;
- var confirmMsg = widget.get('isShared') ? Em.I18n.t('dashboard.widgets.browser.action.delete.shared.bodyMsg').format(widget.widgetName) : Em.I18n.t('dashboard.widgets.browser.action.delete.mine.bodyMsg').format(widget.widgetName);
- var bodyMessage = Em.Object.create({
- confirmMsg: confirmMsg,
- confirmButton: Em.I18n.t('dashboard.widgets.browser.action.delete.btnMsg')
- });
- return App.showConfirmationFeedBackPopup(function (query) {
- return App.ajax.send({
- name: 'widget.action.delete',
- sender: self,
- data: {
- id: widget.id
- },
- success: 'updateWidgetBrowser'
- });
-
- }, bodyMessage);
- },
-
- /**
- * update widget browser content after deleted some widget
- */
- updateWidgetBrowser: function () {
- this.loadAllSharedWidgets();
- this.loadMineWidgets();
- },
-
- /**
- * Share widgets, on click handler for "Share"
- */
- shareWidget: function (event) {
- var widget = event.context;
- var self = this;
- var bodyMessage = Em.Object.create({
- confirmMsg: Em.I18n.t('dashboard.widgets.browser.action.share.confirmation'),
- confirmButton: Em.I18n.t('dashboard.widgets.browser.action.share')
- });
- return App.showConfirmationFeedBackPopup(function (query) {
- return App.ajax.send({
- name: 'widgets.wizard.edit',
- sender: self,
- data: {
- data: {
- "WidgetInfo": {
- "widget_name": widget.get("widgetName"),
- "scope": "CLUSTER"
- }
- },
- widgetId: widget.get("id")
- },
- success: 'updateWidgetBrowser'
- });
- }, bodyMessage);
- },
-
- /**
- * create widget
- */
- createWidget: function () {
- App.router.send('createServiceWidget', Em.Object.create({
- layout: this.get('activeWidgetLayout'),
- serviceName: this.get('content.serviceName')
- }));
- },
-
- /**
- * edit widget
- * @param {App.Widget} content
- */
- editWidget: function (content) {
- content.set('serviceName', this.get('content.serviceName'));
- App.router.send('editServiceWidget', content);
- },
-
- /**
- * launch Widgets Browser popup
- * @method showPopup
- * @return {App.ModalPopup}
- */
- goToWidgetsBrowser: function () {
- var self = this;
-
- return App.ModalPopup.show({
- header: Em.I18n.t('dashboard.widgets.browser.header'),
-
- classNames: ['common-modal-wrapper', 'widgets-browser-popup'],
- modalDialogClasses: ['modal-lg'],
- onPrimary: function () {
- this.hide();
- self.set('isAllSharedWidgetsLoaded', false);
- self.set('allSharedWidgets', []);
- self.set('isMineWidgetsLoaded', false);
- self.set('mineWidgets', []);
- },
- autoHeight: false,
- isHideBodyScroll: false,
- footerClass: Ember.View.extend({
- templateName: require('templates/common/modal_popups/widget_browser_footer'),
- isShowMineOnly: false,
- onPrimary: function() {
- this.get('parentView').onPrimary();
- }
- }),
- isShowMineOnly: false,
- bodyClass: Ember.View.extend({
- templateName: require('templates/common/modal_popups/widget_browser_popup'),
- controller: self,
- willInsertElement: function () {
- this.get('controller').loadAllSharedWidgets();
- this.get('controller').loadMineWidgets();
- },
-
- isLoaded: Em.computed.and('controller.isAllSharedWidgetsLoaded', 'controller.isMineWidgetsLoaded'),
-
- isWidgetEmptyList: Em.computed.empty('filteredContent'),
-
- activeService: '',
- activeStatus: '',
-
- content: function () {
- if (this.get('parentView.isShowMineOnly')) {
- return this.get('controller.mineWidgets');
- } else {
- // merge my widgets and all shared widgets, no duplicated is allowed
- var content = [];
- var widgetMap = {};
- var allWidgets = this.get('controller.allSharedWidgets').concat(this.get('controller.mineWidgets'));
- allWidgets.forEach(function(widget) {
- if (!widgetMap[widget.get("id")]) {
- content.pushObject(widget);
- widgetMap[widget.get("id")] = true;
- }
- });
- return content;
- }
- }.property('controller.allSharedWidgets.length', 'controller.isAllSharedWidgetsLoaded',
- 'controller.mineWidgets.length', 'controller.isMineWidgetsLoaded', 'parentView.isShowMineOnly'),
-
- /**
- * displaying content filtered by service name and status.
- */
- filteredContent: function () {
- var activeService = this.get('activeService') ? this.get('activeService') : this.get('controller.content.serviceName');
- var result = [];
- this.get('content').forEach(function (widget) {
- if (widget.get('serviceName').indexOf(activeService) >= 0) {
- result.pushObject(widget);
- }
- });
- return result;
- }.property('content', 'activeService', 'activeStatus'),
-
- /**
- * service name filter
- */
- services: function () {
- var view = this;
- var services = App.Service.find().filter(function(item){
- var stackService = App.StackService.find().findProperty('serviceName', item.get('serviceName'));
- return stackService.get('isServiceWithWidgets');
- });
- return services.map(function (service) {
- return Em.Object.create({
- value: service.get('serviceName'),
- label: service.get('displayName'),
- isActive: function () {
- var activeService = view.get('activeService') ? view.get('activeService') : view.get('controller.content.serviceName');
- return this.get('value') == activeService;
- }.property('value', 'view.activeService')
- })
- });
- }.property('activeService'),
-
- filterByService: function (event) {
- this.set('activeService', event.context);
- },
-
- createWidget: function () {
- this.get('parentView').onPrimary();
- this.get('controller').createWidget();
- },
-
- ensureTooltip: function () {
- Em.run.later(this, function () {
- App.tooltip($("[rel='shared-icon-tooltip']"));
- }, 1000);
- }.observes('activeService', 'parentView.isShowMineOnly'),
-
- didInsertElement: function () {
- this.ensureTooltip();
- }
- })
- });
- },
-
goToView: function(event) {
App.router.route(event.context.get('internalAmbariUrl'));
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
index e833ead..a46c5e4 100644
--- a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
@@ -417,7 +417,7 @@ App.WidgetWizardController = App.WizardController.extend({
var self = this;
var successCallBack = function() {
self.get('popup').hide();
- App.router.transitionTo('main.services.service.summary', service);
+ App.router.transitionTo('main.services.service.metrics', service);
App.get('router.updateController').updateAll();
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 7cde3d1..3c4f038 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2199,6 +2199,7 @@ Em.I18n.translations = {
'services.service.info.menu.summary':'Summary',
'services.service.info.menu.configs':'Configs',
'services.service.info.menu.heatmaps':'Heatmaps',
+ 'services.service.info.menu.metrics':'Metrics',
'services.service.info.summary.hostsRunningMonitor':'{0}/{1}',
'services.service.info.summary.serversHostCount':'{0} more',
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/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 34a4763..00b46a8 100644
--- a/ambari-web/app/styles/enhanced_service_dashboard.less
+++ b/ambari-web/app/styles/enhanced_service_dashboard.less
@@ -26,6 +26,10 @@
clear: both;
+ .service-widgets-box {
+ padding: 10px 1.1% 10px 1.1%;
+ }
+
#add-widget-action-box {
background-color: @add-widget-btn-color;
width: 97%;
@@ -69,7 +73,7 @@
width: 93%;
}
.span2p4 {
- width: 22.7%;
+ width: 24.4%;
height: 100%;
background-color: white;
margin: 5px 0 5px 5px;
@@ -188,6 +192,26 @@
}
}
+@media (min-width: 1200px) {
+
+ .service-metrics-block .service-widgets-box {
+ padding: 10px 1.3% 10px 1.3%;
+ }
+
+ #widget_layout .span2p4 {
+ width: 24.5%;
+ *width: 24.5%;
+ }
+}
+
+@media (min-width: 1500px) {
+
+ #widget_layout .span2p4 {
+ width: 24.6%;
+ *width: 24.6%;
+ }
+}
+
#widget-preview {
max-width: 200px;
margin: auto;
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/templates/main/service/info/metrics.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/info/metrics.hbs b/ambari-web/app/templates/main/service/info/metrics.hbs
new file mode 100644
index 0000000..6834c06
--- /dev/null
+++ b/ambari-web/app/templates/main/service/info/metrics.hbs
@@ -0,0 +1,104 @@
+{{!
+* 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.serviceHasMetrics}}
+ <div class="service-metrics-block">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="row">
+ <div class="col-md-7 col-lg-7">
+ <h4 class="panel-title">{{t services.service.metrics}}</h4>
+ </div>
+ <div class="col-md-5 col-lg-5">
+ {{#if showTimeRangeControl}}
+ {{view view.timeRangeListView}}
+ {{/if}}
+ {{#if isServiceWithEnhancedWidgets}}
+ {{#if isAmbariMetricsInstalled}}
+ <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="#" {{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}}
+ {{/if}}
+ </li>
+ {{/each}}
+ </ul>
+ </div>
+ {{/if}}
+ {{/if}}
+ </div>
+ </div>
+ </div>
+ <div class="panel-body service-widgets-box">
+ {{#if isServiceWithEnhancedWidgets}}
+ <div id="widget_layout" class="thumbnails">
+ {{#each widget in controller.widgets}}
+ <div class="widget span2p4" {{bindAttr id="widget.id"}}>
+ {{view widget.viewClass contentBinding="widget" idBinding="widget.id"}}
+ </div>
+ {{/each}}
+ {{#if isAmbariMetricsInstalled}}
+ <div class="span2p4">
+ <button id="add-widget-action-box" {{action "goToWidgetsBrowser" controller.content
+ target="controller"}}
+ rel="add-widget-tooltip" {{translateAttr
+ data-original-title="dashboard.widgets.addButton.tooltip"}}>
+ <i class="glyphicon glyphicon-plus"></i></button>
+ </div>
+ {{/if}}
+ </div>
+ {{/if}}
+ <table class="graphs">
+ {{#each graphs in view.serviceMetricGraphs}}
+ <tr>
+ {{#each graph in graphs}}
+ <td>
+ <div>
+ {{view graph}}
+ </div>
+ </td>
+ {{/each}}
+ </tr>
+ {{/each}}
+ </table>
+ </div>
+ </div>
+ </div>
+{{/if}}
+
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/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 075cae0..b0c9e7f 100644
--- a/ambari-web/app/templates/main/service/info/summary.hbs
+++ b/ambari-web/app/templates/main/service/info/summary.hbs
@@ -134,90 +134,6 @@
</div>
</div>
</div>
- {{! widgets in the metrics panel are loaded seperately from summary page text information
- and does not get block due to any global API poller information }}
- {{#if view.isServiceMetricLoaded}}
- <div class="service-metrics-block">
- <div class="panel panel-default">
- <div class="panel-heading">
- <div class="row">
- <div class="col-md-7 col-lg-7">
- <h4 class="panel-title">{{t services.service.metrics}}</h4>
- </div>
- <div class="col-md-5 col-lg-5">
- {{#if showTimeRangeControl}}
- {{view view.timeRangeListView}}
- {{/if}}
- {{#if isServiceWithEnhancedWidgets}}
- {{#if isAmbariMetricsInstalled}}
- <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="#" {{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}}
- {{/if}}
- </li>
- {{/each}}
- </ul>
- </div>
- {{/if}}
- {{/if}}
- </div>
- </div>
- </div>
- <div class="panel-body">
- {{#if isServiceWithEnhancedWidgets}}
- <div id="widget_layout" class="thumbnails">
- {{#each widget in controller.widgets}}
- <div class="widget span2p4" {{bindAttr id="widget.id"}}>
- {{view widget.viewClass contentBinding="widget" idBinding="widget.id"}}
- </div>
- {{/each}}
- {{#if isAmbariMetricsInstalled}}
- <div class="span2p4">
- <button id="add-widget-action-box"
- {{action "goToWidgetsBrowser" controller.content target="controller"}}
- rel="add-widget-tooltip" {{translateAttr data-original-title="dashboard.widgets.addButton.tooltip"}}>
- <i class="glyphicon glyphicon-plus"></i></button>
- </div>
- {{/if}}
- </div>
- {{/if}}
- <table class="graphs">
- {{#each graphs in view.serviceMetricGraphs}}
- <tr>
- {{#each graph in graphs}}
- <td>
- <div>
- {{view graph}}
- </div>
- </td>
- {{/each}}
- </tr>
- {{/each}}
- </table>
- </div>
- </div>
- </div>
- {{/if}}
</div>
{{#if view.collapsedSections}}
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/templates/main/service/item.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/item.hbs b/ambari-web/app/templates/main/service/item.hbs
index e942eb1..df26a9d 100644
--- a/ambari-web/app/templates/main/service/item.hbs
+++ b/ambari-web/app/templates/main/service/item.hbs
@@ -16,7 +16,10 @@
* limitations under the License.
}}
-{{view App.MainServiceInfoMenuView configTabBinding="view.hasConfigTab" heatmapTabBinding="view.hasHeatmapTab"}}
+{{view App.MainServiceInfoMenuView
+ configTabBinding="view.hasConfigTab"
+ heatmapTabBinding="view.hasHeatmapTab"
+ metricTabBinding="view.hasMetricTab"}}
{{#isAuthorized "SERVICE.RUN_CUSTOM_COMMAND, SERVICE.RUN_SERVICE_CHECK, SERVICE.START_STOP, SERVICE.TOGGLE_MAINTENANCE, SERVICE.ENABLE_HA"}}
<div class="service-button">
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 8031434..50729a7 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -348,6 +348,7 @@ require('views/main/charts/heatmap/heatmap_rack');
require('views/main/charts/heatmap/heatmap_host');
require('views/main/charts/heatmap/heatmap_host_detail');
require('views/main/service/info/heatmap_view');
+require('views/main/service/info/metrics_view');
require('views/main/service/widgets/create/wizard_view');
require('views/main/service/widgets/create/step1_view');
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/views/main/service/info/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/menu.js b/ambari-web/app/views/main/service/info/menu.js
index 3533a72..89d5401 100644
--- a/ambari-web/app/views/main/service/info/menu.js
+++ b/ambari-web/app/views/main/service/info/menu.js
@@ -45,6 +45,13 @@ App.MainServiceInfoMenuView = Em.CollectionView.extend({
routing: 'configs'
});
}
+ if (this.get('metricTab')) {
+ menuItems.push({
+ label: Em.I18n.t('services.service.info.menu.metrics'),
+ id: 'metrics-service-tab',
+ routing: 'metrics'
+ });
+ }
return menuItems;
}.property(),
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/views/main/service/info/metrics_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/metrics_view.js b/ambari-web/app/views/main/service/info/metrics_view.js
new file mode 100644
index 0000000..161dce1
--- /dev/null
+++ b/ambari-web/app/views/main/service/info/metrics_view.js
@@ -0,0 +1,290 @@
+/**
+ * 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');
+var misc = require('utils/misc');
+require('views/main/service/service');
+require('data/service_graph_config');
+
+App.MainServiceInfoMetricsView = Em.View.extend(App.Persist, App.TimeRangeMixin, {
+ templateName: require('templates/main/service/info/metrics'),
+ /**
+ * @property {Number} chunkSize - number of columns in Metrics section
+ */
+ chunkSize: 5,
+
+ service: null,
+
+ svc: function () {
+ var svc = this.get('controller.content');
+ var svcName = svc.get('serviceName');
+ if (svcName) {
+ switch (svcName.toLowerCase()) {
+ case 'hdfs':
+ svc = App.HDFSService.find().objectAt(0);
+ break;
+ case 'yarn':
+ svc = App.YARNService.find().objectAt(0);
+ break;
+ case 'hbase':
+ svc = App.HBaseService.find().objectAt(0);
+ break;
+ case 'flume':
+ svc = App.FlumeService.find().objectAt(0);
+ break;
+ default:
+ break;
+ }
+ }
+ return svc;
+ }.property('controller.content.serviceName').volatile(),
+
+ getServiceModel: function (serviceName) {
+ var extended = App.Service.extendedModel[serviceName];
+ if (extended) {
+ return App[extended].find().objectAt(0);
+ }
+ return App.Service.find(serviceName);
+ },
+
+ serviceName: Em.computed.alias('service.serviceName'),
+
+ /**
+ * Contains graphs for this particular service
+ */
+ serviceMetricGraphs: [],
+
+ /**
+ * @type {boolean}
+ * @default false
+ */
+ serviceHasMetrics: false,
+
+ /**
+ * Key-name to store time range in Persist
+ * @type {string}
+ */
+ persistKey: Em.computed.format('time-range-service-{0}', 'service.serviceName'),
+
+ didInsertElement: function () {
+ var svcName = this.get('controller.content.serviceName');
+ this.set('service', this.getServiceModel(svcName));
+ var isMetricsSupported = svcName !== 'STORM' || App.get('isStormMetricsSupported');
+
+ this.get('controller').getActiveWidgetLayout();
+ if (App.get('supports.customizedWidgetLayout')) {
+ this.get('controller').loadWidgetLayouts();
+ }
+
+ if (svcName && isMetricsSupported) {
+ var allServices = require('data/service_graph_config');
+ this.constructGraphObjects(allServices[svcName.toLowerCase()]);
+ }
+ this.makeSortable();
+ this.addWidgetTooltip();
+ },
+
+ addWidgetTooltip: function() {
+ Em.run.later(this, function () {
+ App.tooltip($("[rel='add-widget-tooltip']"));
+ // enable description show up on hover
+ $('.img-thumbnail').hoverIntent(function() {
+ if ($(this).is('hover')) {
+ $(this).find('.hidden-description').delay(1000).fadeIn(200).end();
+ }
+ }, function() {
+ $(this).find('.hidden-description').stop().hide().end();
+ });
+ }, 1000);
+ },
+
+ willDestroyElement: function() {
+ $("[rel='add-widget-tooltip']").tooltip('destroy');
+ $('.img-thumbnail').off();
+ $('#widget_layout').sortable('destroy');
+ $('.widget.span2p4').detach().remove();
+ this.get('serviceMetricGraphs').clear();
+ this.set('service', null);
+ },
+
+ /*
+ * Find the graph class associated with the graph name, and split
+ * the array into sections of 5 for displaying on the page
+ * (will only display rows with 5 items)
+ */
+ constructGraphObjects: function (graphNames) {
+ var self = this,
+ stackService = App.StackService.find(this.get('controller.content.serviceName'));
+
+ if (!graphNames && !stackService.get('isServiceWithWidgets')) {
+ this.get('serviceMetricGraphs').clear();
+ this.set('serviceHasMetrics', false);
+ return;
+ }
+
+ // load time range(currentTimeRangeIndex) for current service from server
+ this.getUserPref(self.get('persistKey')).complete(function () {
+ var result = [], graphObjects = [], chunkSize = self.get('chunkSize');
+ if (graphNames) {
+ graphNames.forEach(function (graphName) {
+ graphObjects.push(App["ChartServiceMetrics" + graphName].extend());
+ });
+ }
+ while (graphObjects.length) {
+ result.push(graphObjects.splice(0, chunkSize));
+ }
+ self.set('serviceMetricGraphs', result);
+ self.set('serviceHasMetrics', true);
+ });
+ },
+
+ getUserPrefSuccessCallback: function (response, request) {
+ if (response) {
+ this.set('currentTimeRangeIndex', response);
+ }
+ },
+
+ getUserPrefErrorCallback: function (request) {
+ if (request.status === 404) {
+ this.postUserPref(this.get('persistKey'), 0);
+ this.set('currentTimeRangeIndex', 0);
+ }
+ },
+
+ /**
+ * list of static actions of widget
+ * @type {Array}
+ */
+ staticGeneralWidgetActions: [
+ Em.Object.create({
+ label: Em.I18n.t('dashboard.widgets.actions.browse'),
+ class: 'glyphicon glyphicon-th',
+ action: 'goToWidgetsBrowser',
+ isAction: true
+ })
+ ],
+
+ /**
+ *list of static actions of widget accessible to Admin/Operator privelege
+ * @type {Array}
+ */
+
+ staticAdminPrivelegeWidgetActions: [
+ Em.Object.create({
+ label: Em.I18n.t('dashboard.widgets.create'),
+ class: 'glyphicon glyphicon-plus',
+ action: 'createWidget',
+ isAction: true
+ })
+ ],
+
+ /**
+ * List of static actions related to widget layout
+ */
+ staticWidgetLayoutActions: [
+ Em.Object.create({
+ label: Em.I18n.t('dashboard.widgets.layout.save'),
+ class: 'glyphicon glyphicon-download-alt',
+ action: 'saveLayout',
+ isAction: true
+ }),
+ Em.Object.create({
+ label: Em.I18n.t('dashboard.widgets.layout.import'),
+ class: 'glyphicon glyphicon-file',
+ isAction: true,
+ layouts: App.WidgetLayout.find()
+ })
+ ],
+
+ /**
+ * @type {Array}
+ */
+ widgetActions: function() {
+ var options = [];
+ if (App.isAuthorized('SERVICE.MODIFY_CONFIGS')) {
+ if (App.supports.customizedWidgetLayout) {
+ options.pushObjects(this.get('staticWidgetLayoutActions'));
+ }
+ options.pushObjects(this.get('staticAdminPrivelegeWidgetActions'));
+ }
+ options.pushObjects(this.get('staticGeneralWidgetActions'));
+ return options;
+ }.property(''),
+
+ /**
+ * 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'));
+ }
+ },
+
+ /**
+ * onclick handler for a time range option
+ * @param {object} event
+ */
+ setTimeRange: function (event) {
+ var graphs = this.get('controller.widgets').filterProperty('widgetType', 'GRAPH'),
+ callback = function () {
+ graphs.forEach(function (widget) {
+ widget.set('properties.time_range', event.context.value);
+ });
+ };
+ this._super(event, callback);
+
+ // Preset time range is specified by user
+ if (event.context.value !== '0') {
+ callback();
+ }
+ },
+
+ /**
+ * Define if some widget is currently moving
+ * @type {boolean}
+ */
+ isMoving: false,
+
+ /**
+ * Make widgets' list sortable on New Dashboard style
+ */
+ makeSortable: function () {
+ var self = this;
+ $('html').on('DOMNodeInserted', '#widget_layout', function () {
+ $(this).sortable({
+ items: "> div",
+ cursor: "move",
+ tolerance: "pointer",
+ scroll: false,
+ update: function () {
+ var widgets = misc.sortByOrder($("#widget_layout .widget").map(function () {
+ return this.id;
+ }), self.get('controller.widgets'));
+ self.get('controller').saveWidgetLayout(widgets);
+ },
+ activate: function () {
+ self.set('isMoving', true);
+ },
+ deactivate: function () {
+ self.set('isMoving', false);
+ }
+ }).disableSelection();
+ $('html').off('DOMNodeInserted', '#widget_layout');
+ });
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/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 91b2ca3..a4769e6 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -21,13 +21,10 @@ var misc = require('utils/misc');
require('views/main/service/service');
require('data/service_graph_config');
-App.MainServiceInfoSummaryView = Em.View.extend(App.Persist, App.TimeRangeMixin, {
+App.MainServiceInfoSummaryView = Em.View.extend({
templateName: require('templates/main/service/info/summary'),
- /**
- * @property {Number} chunkSize - number of columns in Metrics section
- */
- chunkSize: 5,
- attributes:null,
+
+ attributes: null,
/**
* Contain array with list of master components from <code>App.Service.hostComponets</code> which are
@@ -165,6 +162,47 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.Persist, App.TimeRangeMixin,
Em.run.once(self, 'setComponentsContent');
}.observes('service.hostComponents.length', 'service.slaveComponents.@each.totalCount', 'service.clientComponents.@each.totalCount'),
+ loadServiceSummary: function () {
+ var serviceName = this.get('serviceName');
+ var serviceSummaryView = null;
+
+ if (!serviceName) {
+ return;
+ }
+
+ if (this.get('oldServiceName')) {
+ // do not delete it!
+ return;
+ }
+
+ var customServiceView = this.get('serviceCustomViewsMap')[serviceName];
+ if (customServiceView) {
+ serviceSummaryView = customServiceView.extend({
+ service: this.get('service')
+ });
+ } else {
+ serviceSummaryView = Em.View.extend(App.MainDashboardServiceViewWrapper, {
+ templateName: this.get('templatePathPrefix') + 'base'
+ });
+ }
+ this.set('serviceSummaryView', serviceSummaryView);
+ this.set('oldServiceName', serviceName);
+ }.observes('serviceName'),
+
+ didInsertElement: function () {
+ this._super();
+ var svcName = this.get('controller.content.serviceName');
+ this.set('service', this.getServiceModel(svcName));
+ App.loadTimer.finish('Service Summary Page');
+ },
+
+ willDestroyElement: function() {
+ this.set('service', null);
+ this.get('mastersObj').clear();
+ this.get('slavesObj').clear();
+ this.get('clientObj').clear();
+ },
+
setComponentsContent: function() {
Em.run.next(function() {
if (Em.isNone(this.get('service'))) {
@@ -372,270 +410,5 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.Persist, App.TimeRangeMixin,
rollingRestartStaleConfigSlaveComponents: function (componentName) {
batchUtils.launchHostComponentRollingRestart(componentName.context, this.get('service.displayName'), this.get('service.passiveState') === "ON", true);
- },
-
- /*
- * Find the graph class associated with the graph name, and split
- * the array into sections of 5 for displaying on the page
- * (will only display rows with 5 items)
- */
- constructGraphObjects: function (graphNames) {
- var self = this,
- stackService = App.StackService.find(this.get('controller.content.serviceName'));
-
- if (!graphNames && !stackService.get('isServiceWithWidgets')) {
- this.get('serviceMetricGraphs').clear();
- this.set('isServiceMetricLoaded', false);
- return;
- }
-
- // load time range(currentTimeRangeIndex) for current service from server
- this.getUserPref(self.get('persistKey')).complete(function () {
- var result = [], graphObjects = [], chunkSize = self.get('chunkSize');
- if (graphNames) {
- graphNames.forEach(function (graphName) {
- graphObjects.push(App["ChartServiceMetrics" + graphName].extend());
- });
- }
- while (graphObjects.length) {
- result.push(graphObjects.splice(0, chunkSize));
- }
- self.set('serviceMetricGraphs', result);
- self.set('isServiceMetricLoaded', true);
- });
- },
-
- /**
- * Contains graphs for this particular service
- */
- serviceMetricGraphs: [],
-
- /**
- * @type {boolean}
- * @default false
- */
- isServiceMetricLoaded: false,
-
- /**
- * Key-name to store time range in Persist
- * @type {string}
- */
- persistKey: Em.computed.format('time-range-service-{0}', 'service.serviceName'),
-
- getUserPrefSuccessCallback: function (response, request) {
- if (response) {
- this.set('currentTimeRangeIndex', response);
- }
- },
-
- getUserPrefErrorCallback: function (request) {
- if (request.status === 404) {
- this.postUserPref(this.get('persistKey'), 0);
- this.set('currentTimeRangeIndex', 0);
- }
- },
-
- /**
- * list of static actions of widget
- * @type {Array}
- */
- staticGeneralWidgetActions: [
- Em.Object.create({
- label: Em.I18n.t('dashboard.widgets.actions.browse'),
- class: 'glyphicon glyphicon-th',
- action: 'goToWidgetsBrowser',
- isAction: true
- })
- ],
-
- /**
- *list of static actions of widget accessible to Admin/Operator privelege
- * @type {Array}
- */
-
- staticAdminPrivelegeWidgetActions: [
- Em.Object.create({
- label: Em.I18n.t('dashboard.widgets.create'),
- class: 'glyphicon glyphicon-plus',
- action: 'createWidget',
- isAction: true
- })
- ],
-
- /**
- * List of static actions related to widget layout
- */
- staticWidgetLayoutActions: [
- Em.Object.create({
- label: Em.I18n.t('dashboard.widgets.layout.save'),
- class: 'glyphicon glyphicon-download-alt',
- action: 'saveLayout',
- isAction: true
- }),
- Em.Object.create({
- label: Em.I18n.t('dashboard.widgets.layout.import'),
- class: 'glyphicon glyphicon-file',
- isAction: true,
- layouts: App.WidgetLayout.find()
- })
- ],
-
- /**
- * @type {Array}
- */
- widgetActions: function() {
- var options = [];
- if (App.isAuthorized('SERVICE.MODIFY_CONFIGS')) {
- if (App.supports.customizedWidgetLayout) {
- options.pushObjects(this.get('staticWidgetLayoutActions'));
- }
- options.pushObjects(this.get('staticAdminPrivelegeWidgetActions'));
- }
- options.pushObjects(this.get('staticGeneralWidgetActions'));
- return options;
- }.property(''),
-
- /**
- * 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'));
- }
- },
-
- /**
- * onclick handler for a time range option
- * @param {object} event
- */
- setTimeRange: function (event) {
- var graphs = this.get('controller.widgets').filterProperty('widgetType', 'GRAPH'),
- callback = function () {
- graphs.forEach(function (widget) {
- widget.set('properties.time_range', event.context.value);
- });
- };
- this._super(event, callback);
-
- // Preset time range is specified by user
- if (event.context.value !== '0') {
- callback();
- }
- },
-
- loadServiceSummary: function () {
- var serviceName = this.get('serviceName');
- var serviceSummaryView = null;
-
- if (!serviceName) {
- return;
- }
-
- if (this.get('oldServiceName')) {
- // do not delete it!
- return;
- }
-
- var customServiceView = this.get('serviceCustomViewsMap')[serviceName];
- if (customServiceView) {
- serviceSummaryView = customServiceView.extend({
- service: this.get('service')
- });
- } else {
- serviceSummaryView = Em.View.extend(App.MainDashboardServiceViewWrapper, {
- templateName: this.get('templatePathPrefix') + 'base'
- });
- }
- this.set('serviceSummaryView', serviceSummaryView);
- this.set('oldServiceName', serviceName);
- }.observes('serviceName'),
-
-
- /**
- * Service metrics panel not displayed when metrics service (ex:Ganglia) is not in stack definition.
- *
- * @type {boolean}
- */
- isNoServiceMetricsService: Em.computed.equal('App.services.serviceMetrics.length', 0),
-
- didInsertElement: function () {
- this._super();
- var svcName = this.get('controller.content.serviceName');
- this.set('service', this.getServiceModel(svcName));
- var isMetricsSupported = svcName !== 'STORM' || App.get('isStormMetricsSupported');
-
- this.get('controller').getActiveWidgetLayout();
- if (App.get('supports.customizedWidgetLayout')) {
- this.get('controller').loadWidgetLayouts();
- }
-
- if (svcName && isMetricsSupported) {
- var allServices = require('data/service_graph_config');
- this.constructGraphObjects(allServices[svcName.toLowerCase()]);
- }
- this.makeSortable();
- this.addWidgetTooltip();
- App.loadTimer.finish('Service Summary Page');
- },
-
- addWidgetTooltip: function() {
- Em.run.later(this, function () {
- App.tooltip($("[rel='add-widget-tooltip']"));
- // enable description show up on hover
- $('.img-thumbnail').hoverIntent(function() {
- if ($(this).is('hover')) {
- $(this).find('.hidden-description').delay(1000).fadeIn(200).end();
- }
- }, function() {
- $(this).find('.hidden-description').stop().hide().end();
- });
- }, 1000);
- },
-
- willDestroyElement: function() {
- $("[rel='add-widget-tooltip']").tooltip('destroy');
- $('.img-thumbnail').off();
- $('#widget_layout').sortable('destroy');
- $('.widget.span2p4').detach().remove();
- this.get('serviceMetricGraphs').clear();
- this.set('service', null);
- this.get('mastersObj').clear();
- this.get('slavesObj').clear();
- this.get('clientObj').clear();
- },
-
- /**
- * Define if some widget is currently moving
- * @type {boolean}
- */
- isMoving: false,
-
- /**
- * Make widgets' list sortable on New Dashboard style
- */
- makeSortable: function () {
- var self = this;
- $('html').on('DOMNodeInserted', '#widget_layout', function () {
- $(this).sortable({
- items: "> div",
- cursor: "move",
- tolerance: "pointer",
- scroll: false,
- update: function () {
- var widgets = misc.sortByOrder($("#widget_layout .widget").map(function () {
- return this.id;
- }), self.get('controller.widgets'));
- self.get('controller').saveWidgetLayout(widgets);
- },
- activate: function () {
- self.set('isMoving', true);
- },
- deactivate: function () {
- self.set('isMoving', false);
- }
- }).disableSelection();
- $('html').off('DOMNodeInserted', '#widget_layout');
- });
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/app/views/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js
index 43d75e6..45c783b 100644
--- a/ambari-web/app/views/main/service/item.js
+++ b/ambari-web/app/views/main/service/item.js
@@ -326,6 +326,12 @@ App.MainServiceItemView = Em.View.extend({
return App.get('services.servicesWithHeatmapTab').contains(this.get('controller.content.serviceName'));
}.property('controller.content.serviceName', 'App.services.servicesWithHeatmapTab'),
+ hasMetricTab: function() {
+ let serviceName = this.get('controller.content.serviceName');
+ let graphs = require('data/service_graph_config')[serviceName.toLowerCase()];
+ return graphs || App.StackService.find(serviceName).get('isServiceWithWidgets');
+ }.property('controller.content.serviceName'),
+
didInsertElement: function () {
this.get('controller').setStartStopState();
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/test/controllers/main/service/info/metric_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/info/metric_test.js b/ambari-web/test/controllers/main/service/info/metric_test.js
new file mode 100644
index 0000000..5ef6279
--- /dev/null
+++ b/ambari-web/test/controllers/main/service/info/metric_test.js
@@ -0,0 +1,110 @@
+/**
+ * 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');
+require('controllers/main/service/info/metric');
+var testHelpers = require('test/helpers');
+function getController() {
+ return App.MainServiceInfoMetricsController.create();
+}
+
+describe('App.MainServiceInfoMetricsController', function () {
+
+ var controller;
+
+ beforeEach(function () {
+ controller = App.MainServiceInfoMetricsController.create();
+ });
+
+ App.TestAliases.testAsComputedOr(getController(), 'showTimeRangeControl', ['!isServiceWithEnhancedWidgets', 'someWidgetGraphExists']);
+
+
+ describe("#getActiveWidgetLayout() for Enhanced Dashboard", function () {
+
+ it("make GET call", function () {
+ controller.reopen({
+ isServiceWithEnhancedWidgets: true,
+ content: Em.Object.create({serviceName: 'HDFS'})
+ });
+ controller.getActiveWidgetLayout();
+ expect(testHelpers.findAjaxRequest('name', 'widgets.layouts.active.get')).to.exists;
+ });
+ });
+
+ describe("#getActiveWidgetLayoutSuccessCallback()", function () {
+ beforeEach(function () {
+ sinon.stub( App.widgetLayoutMapper, 'map');
+ sinon.stub( App.widgetMapper, 'map');
+ });
+ afterEach(function () {
+ App.widgetLayoutMapper.map.restore();
+ App.widgetMapper.map.restore();
+ });
+ it("isWidgetLayoutsLoaded should be set to true", function () {
+ controller.reopen({
+ isServiceWithEnhancedWidgets: true,
+ content: Em.Object.create({serviceName: 'HDFS'})
+ });
+ controller.getActiveWidgetLayoutSuccessCallback({items:[{
+ WidgetLayoutInfo: {}
+ }]});
+ expect(controller.get('isWidgetsLoaded')).to.be.true;
+ });
+
+ });
+
+ describe("#hideWidgetSuccessCallback()", function () {
+ beforeEach(function () {
+ sinon.stub(App.widgetLayoutMapper, 'map');
+ sinon.stub(controller, 'propertyDidChange');
+ var params = {
+ data: {
+ WidgetLayoutInfo: {
+ widgets: [
+ {id: 1}
+ ]
+ }
+ }
+ };
+ controller.hideWidgetSuccessCallback({}, {}, params);
+ });
+ afterEach(function () {
+ App.widgetLayoutMapper.map.restore();
+ controller.propertyDidChange.restore();
+ });
+ it("mapper is called with valid data", function () {
+ expect(App.widgetLayoutMapper.map.calledWith({
+ items: [{
+ WidgetLayoutInfo: {
+ widgets: [
+ {
+ WidgetInfo: {
+ id: 1
+ }
+ }
+ ]
+ }
+ }]
+ })).to.be.true;
+ });
+ it('`widgets` is forced to be recalculated', function () {
+ expect(controller.propertyDidChange.calledWith('widgets')).to.be.true;
+ });
+ });
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/test/controllers/main/service/info/summary_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/info/summary_test.js b/ambari-web/test/controllers/main/service/info/summary_test.js
index 51dd595..e5cc32a 100644
--- a/ambari-web/test/controllers/main/service/info/summary_test.js
+++ b/ambari-web/test/controllers/main/service/info/summary_test.js
@@ -18,7 +18,6 @@
var App = require('app');
require('controllers/main/service/info/summary');
-var testHelpers = require('test/helpers');
function getController() {
return App.MainServiceInfoSummaryController.create();
}
@@ -31,8 +30,6 @@ describe('App.MainServiceInfoSummaryController', function () {
controller = App.MainServiceInfoSummaryController.create();
});
-App.TestAliases.testAsComputedOr(getController(), 'showTimeRangeControl', ['!isServiceWithEnhancedWidgets', 'someWidgetGraphExists']);
-
describe('#setRangerPlugins', function () {
var cases = [
@@ -184,77 +181,4 @@ App.TestAliases.testAsComputedOr(getController(), 'showTimeRangeControl', ['!isS
});
- describe("#getActiveWidgetLayout() for Enhanced Dashboard", function () {
-
- it("make GET call", function () {
- var _controller = App.MainServiceInfoSummaryController.create({
- isServiceWithEnhancedWidgets: true,
- content: Em.Object.create({serviceName: 'HDFS'})
- });
- _controller.getActiveWidgetLayout();
- expect(testHelpers.findAjaxRequest('name', 'widgets.layouts.active.get')).to.exists;
- });
- });
-
- describe("#getActiveWidgetLayoutSuccessCallback()", function () {
- beforeEach(function () {
- sinon.stub( App.widgetLayoutMapper, 'map');
- sinon.stub( App.widgetMapper, 'map');
- });
- afterEach(function () {
- App.widgetLayoutMapper.map.restore();
- App.widgetMapper.map.restore();
- });
- it("isWidgetLayoutsLoaded should be set to true", function () {
- var _controller = App.MainServiceInfoSummaryController.create({
- isServiceWithEnhancedWidgets: true,
- content: Em.Object.create({serviceName: 'HDFS'})
- });
- _controller.getActiveWidgetLayoutSuccessCallback({items:[{
- WidgetLayoutInfo: {}
- }]});
- expect(_controller.get('isWidgetsLoaded')).to.be.true;
- });
-
- });
-
- describe("#hideWidgetSuccessCallback()", function () {
- beforeEach(function () {
- sinon.stub(App.widgetLayoutMapper, 'map');
- sinon.stub(controller, 'propertyDidChange');
- var params = {
- data: {
- WidgetLayoutInfo: {
- widgets: [
- {id: 1}
- ]
- }
- }
- };
- controller.hideWidgetSuccessCallback({}, {}, params);
- });
- afterEach(function () {
- App.widgetLayoutMapper.map.restore();
- controller.propertyDidChange.restore();
- });
- it("mapper is called with valid data", function () {
- expect(App.widgetLayoutMapper.map.calledWith({
- items: [{
- WidgetLayoutInfo: {
- widgets: [
- {
- WidgetInfo: {
- id: 1
- }
- }
- ]
- }
- }]
- })).to.be.true;
- });
- it('`widgets` is forced to be recalculated', function () {
- expect(controller.propertyDidChange.calledWith('widgets')).to.be.true;
- });
- });
-
});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/6eb273e1/ambari-web/test/views/main/service/info/metrics_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/metrics_view_test.js b/ambari-web/test/views/main/service/info/metrics_view_test.js
new file mode 100644
index 0000000..916d451
--- /dev/null
+++ b/ambari-web/test/views/main/service/info/metrics_view_test.js
@@ -0,0 +1,334 @@
+/**
+ * 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');
+require('views/main/service/info/metrics_view');
+
+describe('App.MainServiceInfoMetricsView', function() {
+
+ var view = App.MainServiceInfoMetricsView.create({
+ controller: Em.Object.create({
+ content: Em.Object.create({
+ id: 'HDFS',
+ serviceName: 'HDFS',
+ hostComponents: []
+ }),
+ getActiveWidgetLayout: Em.K,
+ loadWidgetLayouts: Em.K
+ }),
+ service: Em.Object.create()
+ });
+
+ describe("#getServiceModel()", function() {
+
+ beforeEach(function() {
+ sinon.stub(App.Service, 'find').returns({serviceName: 'S1'});
+ sinon.stub(App.HDFSService, 'find').returns([{serviceName: 'HDFS'}]);
+ });
+ afterEach(function() {
+ App.Service.find.restore();
+ App.HDFSService.find.restore();
+ });
+
+ it("HDFS service", function() {
+ expect(view.getServiceModel('HDFS')).to.eql({serviceName: 'HDFS'});
+ });
+
+ it("Simple model service", function() {
+ expect(view.getServiceModel('S1')).to.eql({serviceName: 'S1'});
+ });
+ });
+
+ describe("#constructGraphObjects()", function() {
+ var mock = Em.Object.create({
+ isServiceWithWidgets: false
+ });
+
+ beforeEach(function() {
+ sinon.stub(App.StackService, 'find').returns(mock);
+ sinon.stub(view, 'getUserPref').returns({
+ complete: function(callback){callback();}
+ })
+ });
+ afterEach(function() {
+ App.StackService.find.restore();
+ view.getUserPref.restore();
+ });
+
+ it("metrics not loaded", function() {
+ mock.set('isServiceWithWidgets', false);
+ view.constructGraphObjects(null);
+ expect(view.get('serviceHasMetrics')).to.be.false;
+ expect(view.getUserPref.called).to.be.false;
+ });
+
+ it("metrics loaded", function() {
+ App.ChartServiceMetricsG1 = Em.Object.extend();
+ mock.set('isServiceWithWidgets', true);
+ view.constructGraphObjects(['G1']);
+ expect(view.get('serviceHasMetrics')).to.be.true;
+ expect(view.getUserPref.calledOnce).to.be.true;
+ expect(view.get('serviceMetricGraphs')).to.not.be.empty;
+ });
+ });
+
+ describe("#getUserPrefSuccessCallback()", function() {
+
+ it("currentTimeRangeIndex should be set", function() {
+ view.getUserPrefSuccessCallback(1);
+ expect(view.get('currentTimeRangeIndex')).to.equal(1);
+ });
+ });
+
+ describe("#getUserPrefErrorCallback()", function() {
+
+ beforeEach(function() {
+ sinon.stub(view, 'postUserPref');
+ });
+ afterEach(function() {
+ view.postUserPref.restore();
+ });
+
+ it("request.status = 404", function() {
+ view.getUserPrefErrorCallback({status: 404});
+ expect(view.get('currentTimeRangeIndex')).to.equal(0);
+ expect(view.postUserPref.calledOnce).to.be.true;
+ });
+
+ it("request.status = 403", function() {
+ view.getUserPrefErrorCallback({status: 403});
+ expect(view.postUserPref.called).to.be.false;
+ });
+ });
+
+ describe("#widgetActions", function() {
+
+ beforeEach(function() {
+ this.mock = sinon.stub(App, 'isAuthorized');
+ view.setProperties({
+ staticWidgetLayoutActions: [{id: 1}],
+ staticAdminPrivelegeWidgetActions: [{id: 2}],
+ staticGeneralWidgetActions: [{id: 3}]
+ });
+ });
+ afterEach(function() {
+ this.mock.restore();
+ });
+
+ it("not authorized", function() {
+ this.mock.returns(false);
+ view.propertyDidChange('widgetActions');
+ expect(view.get('widgetActions').mapProperty('id')).to.eql([3]);
+ });
+
+ it("is authorized", function() {
+ this.mock.returns(true);
+ App.supports.customizedWidgetLayout = true;
+ view.propertyDidChange('widgetActions');
+ expect(view.get('widgetActions').mapProperty('id')).to.eql([1, 2, 3]);
+ });
+ });
+
+ describe("#doWidgetAction()", function() {
+
+ beforeEach(function() {
+ view.set('controller.action1', Em.K);
+ sinon.stub(view.get('controller'), 'action1');
+ });
+ afterEach(function() {
+ view.get('controller').action1.restore();
+ });
+
+ it("action exist", function() {
+ view.doWidgetAction({context: 'action1'});
+ expect(view.get('controller').action1.calledOnce).to.be.true;
+ });
+ });
+
+ describe("#setTimeRange", function() {
+
+ it("range = 0", function() {
+ var widget = Em.Object.create({
+ widgetType: 'GRAPH',
+ properties: {
+ time_range: '0'
+ }
+ });
+ view.set('controller.widgets', [widget]);
+ view.setTimeRange({context: {value: '0'}});
+ expect(widget.get('properties').time_range).to.be.equal('0')
+ });
+
+ it("range = 1", function() {
+ var widget = Em.Object.create({
+ widgetType: 'GRAPH',
+ properties: {
+ time_range: 0
+ }
+ });
+ view.set('controller.widgets', [widget]);
+ view.setTimeRange({context: {value: '1'}});
+ expect(widget.get('properties').time_range).to.be.equal('1')
+ });
+ });
+
+ describe("#makeSortable()", function() {
+ var mock = {
+ on: function(arg1, arg2, callback) {
+ callback();
+ },
+ off: Em.K,
+ sortable: function() {
+ return {
+ disableSelection: Em.K
+ }
+ }
+ };
+
+ beforeEach(function() {
+ sinon.stub(window, '$').returns(mock);
+ sinon.spy(mock, 'on');
+ sinon.spy(mock, 'off');
+ sinon.spy(mock, 'sortable');
+ view.makeSortable();
+ });
+ afterEach(function() {
+ window.$.restore();
+ mock.on.restore();
+ mock.off.restore();
+ mock.sortable.restore();
+ });
+
+ it("on() should be called", function() {
+ expect(mock.on.calledWith('DOMNodeInserted', '#widget_layout')).to.be.true;
+ });
+
+ it("sortable() should be called", function() {
+ expect(mock.sortable.calledOnce).to.be.true;
+ });
+
+ it("off() should be called", function() {
+ expect(mock.off.calledWith('DOMNodeInserted', '#widget_layout')).to.be.true;
+ });
+ });
+
+ describe('#didInsertElement', function () {
+
+ beforeEach(function () {
+ sinon.stub(view, 'constructGraphObjects', Em.K);
+ this.mock = sinon.stub(App, 'get');
+ sinon.stub(view, 'getServiceModel');
+ sinon.stub(view.get('controller'), 'getActiveWidgetLayout');
+ sinon.stub(view.get('controller'), 'loadWidgetLayouts');
+ sinon.stub(view, 'makeSortable');
+ sinon.stub(view, 'addWidgetTooltip');
+
+ });
+
+ afterEach(function () {
+ view.constructGraphObjects.restore();
+ this.mock.restore();
+ view.getServiceModel.restore();
+ view.get('controller').getActiveWidgetLayout.restore();
+ view.get('controller').loadWidgetLayouts.restore();
+ view.makeSortable.restore();
+ view.addWidgetTooltip.restore();
+ });
+
+ it("getServiceModel should be called", function() {
+ view.didInsertElement();
+ expect(view.getServiceModel.calledOnce).to.be.true;
+ });
+ it("addWidgetTooltip should be called", function() {
+ view.didInsertElement();
+ expect(view.addWidgetTooltip.calledOnce).to.be.true;
+ });
+ it("makeSortable should be called", function() {
+ view.didInsertElement();
+ expect(view.makeSortable.calledOnce).to.be.true;
+ });
+ it("getActiveWidgetLayout should be called", function() {
+ view.didInsertElement();
+ expect(view.get('controller').getActiveWidgetLayout.calledOnce).to.be.true;
+ });
+
+ describe("serviceName is null, metrics not supported, widgets not supported", function() {
+ beforeEach(function () {
+ view.set('controller.content.serviceName', null);
+ this.mock.returns(false);
+ view.didInsertElement();
+ });
+
+ it("loadWidgetLayouts should not be called", function() {
+ expect(view.get('controller').loadWidgetLayouts.called).to.be.false;
+ });
+ it("constructGraphObjects should not be called", function() {
+ expect(view.constructGraphObjects.called).to.be.false;
+ });
+ });
+
+ describe("serviceName is set, metrics is supported, widgets is supported", function() {
+ beforeEach(function () {
+ view.set('controller.content.serviceName', 'S1');
+ this.mock.returns(true);
+ view.didInsertElement();
+ });
+
+ it("loadWidgetLayouts should be called", function() {
+ expect(view.get('controller').loadWidgetLayouts.calledOnce).to.be.true;
+ });
+ it("constructGraphObjects should be called", function() {
+ expect(view.constructGraphObjects.calledOnce).to.be.true;
+ });
+ });
+ });
+
+ describe("#addWidgetTooltip()", function() {
+ var mock = {
+ hoverIntent: Em.K
+ };
+
+ beforeEach(function() {
+ sinon.stub(Em.run, 'later', function(arg1, callback) {
+ callback();
+ });
+ sinon.stub(App, 'tooltip');
+ sinon.stub(window, '$').returns(mock);
+ sinon.spy(mock, 'hoverIntent');
+ view.addWidgetTooltip();
+ });
+ afterEach(function() {
+ Em.run.later.restore();
+ App.tooltip.restore();
+ window.$.restore();
+ mock.hoverIntent.restore();
+ });
+
+ it("Em.run.later should be called", function() {
+ expect(Em.run.later.calledOnce).to.be.true;
+ });
+ it("App.tooltip should be called", function() {
+ expect(App.tooltip.calledOnce).to.be.true;
+ });
+ it("hoverIntent should be called", function() {
+ expect(mock.hoverIntent.calledOnce).to.be.true;
+ });
+ });
+
+});
\ No newline at end of file