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 2015/03/27 17:11:43 UTC
ambari git commit: AMBARI-10223 Draw Number widget from the relevant
retrieved widget data from the API. (atkach)
Repository: ambari
Updated Branches:
refs/heads/trunk 391cc7a6f -> bfb586d85
AMBARI-10223 Draw Number widget from the relevant retrieved widget data from the API. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/bfb586d8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/bfb586d8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/bfb586d8
Branch: refs/heads/trunk
Commit: bfb586d8562c7ffe54e9f313f0eac22389e075f5
Parents: 391cc7a
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Fri Mar 27 17:19:26 2015 +0200
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Fri Mar 27 18:11:33 2015 +0200
----------------------------------------------------------------------
.../HBASE/Append_num_ops_&_Delete_num_ops.json | 7 +-
.../data/widget_layouts/HBASE/stack_layout.json | 116 ---------
ambari-web/app/assets/test/tests.js | 1 +
ambari-web/app/mixins.js | 1 +
ambari-web/app/mixins/common/widget_mixin.js | 179 ++++++++++++++
ambari-web/app/models/widget.js | 2 +
ambari-web/app/styles/widget_layout.less | 39 +++
.../templates/common/widget/template_widget.hbs | 22 ++
.../app/templates/main/service/info/summary.hbs | 6 +-
ambari-web/app/views.js | 1 +
.../views/common/widget/graph_widget_view.js | 153 +-----------
.../views/common/widget/template_widget_view.js | 96 ++++++++
.../test/mixins/common/widget_mixin_test.js | 238 +++++++++++++++++++
13 files changed, 594 insertions(+), 267 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/ambari-web/app/assets/data/metrics/HBASE/Append_num_ops_&_Delete_num_ops.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/metrics/HBASE/Append_num_ops_&_Delete_num_ops.json b/ambari-web/app/assets/data/metrics/HBASE/Append_num_ops_&_Delete_num_ops.json
index 97d1bee..2db12a0 100644
--- a/ambari-web/app/assets/data/metrics/HBASE/Append_num_ops_&_Delete_num_ops.json
+++ b/ambari-web/app/assets/data/metrics/HBASE/Append_num_ops_&_Delete_num_ops.json
@@ -1,4 +1,3 @@
-
{
"href" : "http://c6401.ambari.apache.org:8080/api/v1/clusters/c1/services/HBASE/components/HBASE_REGIONSERVER?fields=metrics/hbase/regionserver/Server/Append_num_ops[1426795139,1426798739,15]",
"ServiceComponentInfo" : {
@@ -8,8 +7,14 @@
},
"metrics" : {
"hbase" : {
+ "ipc" : {
+ "IPC" : {
+ "numOpenConnections" : 11.5
+ }
+ },
"regionserver" : {
"Server" : {
+ "percentFilesLocal" : 99,
"Append_num_ops" : [
[
2.0,
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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 f921ad7..4c8d3ee 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
@@ -19,21 +19,6 @@
"widget_type": "GRAPH",
"metrics":[
{
- "name": "regionserver.Server.Get_num_ops",
- "widget_id": "metrics/hbase/regionserver/Server/Get_num_ops",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER",
- "host_component_criteria" : "isActive=true"
- },
- {
- "name": "regionserver.Server.Scan_num_ops",
- "widget_id": "metrics/hbase/regionserver/Server/Scan_num_ops",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- },
- {
"name": "regionserver.Server.Append_num_ops",
"widget_id": "metrics/hbase/regionserver/Server/Append_num_ops",
"category": "",
@@ -46,20 +31,6 @@
"category": "",
"service_name": "HBASE",
"component_name": "HBASE_REGIONSERVER"
- },
- {
- "name": "regionserver.Server.Increment_num_ops",
- "widget_id": "metrics/hbase/regionserver/Server/Increment_num_ops",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- },
- {
- "name": "regionserver.Server.Mutate_num_ops",
- "widget_id": "metrics/hbase/regionserver/Server/Mutate_num_ops",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
}
],
"values": [
@@ -79,67 +50,6 @@
}
},
{
- "widget_name": "OPEN_CONNECTIONS",
- "display_name": "Open Connections",
- "description": "This widget shows number of current open connections",
- "widget_type": "GRAPH",
- "metrics":[
- {
- "name": "ipc.IPC.numOpenConnections",
- "widget_id": "metrics/hbase/ipc/IPC/numOpenConnections",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- }
- ],
- "values": [
- {
- "name": "Open Connections",
- "value": "${ipc.IPC.numOpenConnections}"
- }
- ],
- "properties": {
- "display_unit": "Connections",
- "graph_type": "STACK",
- "time_range": "1 hour"
- }
- },
- {
- "widget_name": "ACTIVE_HANDLER",
- "display_name": "Active Handlers vs Calls in General Queue",
- "widget_type": "GRAPH",
- "metrics":[
- {
- "name": "ipc.IPC.numOpenConnections",
- "widget_id": "metrics/hbase/ipc/IPC/numOpenConnections",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- },
- {
- "name": "ipc.IPC.numCallsInGeneralQueue",
- "widget_id": "metrics/hbase/ipc/IPC/numOpenConnections",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- }
- ],
- "values": [
- {
- "name": "Active Handlers",
- "value": "${ipc.IPC.numActiveHandler}"
- },
- {
- "name": "Calls in General Queue",
- "value": "${ipc.IPC.numCallsInGeneralQueue}"
- }
- ],
- "properties": {
- "graph_type": "LINE",
- "time_range": "1 hour"
- }
- },
- {
"widget_name": "FILES_LOCAL",
"display_name": "Files Local",
"description": "This widget shows percentage of files local.",
@@ -162,32 +72,6 @@
"properties": {
"display_unit": "%"
}
- },
- {
- "widget_name": "UPDATED_BLOCKED_TIME",
- "display_name": "Updated Blocked Time",
- "description": "",
- "widget_type": "GRAPH",
- "metrics":[
- {
- "name": "regionserver.Server.updatesBlockedTime",
- "widget_id": "metrics/hbase/regionserver/Server/updatesBlockedTime",
- "category": "",
- "service_name": "HBASE",
- "component_name": "HBASE_REGIONSERVER"
- }
- ],
- "values": [
- {
- "name": "Updated Blocked Time",
- "value": "${regionserver.Server.updatesBlockedTime}"
- }
- ],
- "properties": {
- "display_unit": "seconds",
- "graph_type": "LINE",
- "time_range": "1 day"
- }
}
]
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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 c668a9f..01dbdb3 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -141,6 +141,7 @@ var files = ['test/init_model_test',
'test/mixins/common/reload_popup_test',
'test/mixins/common/serverValidator_test',
'test/mixins/common/table_server_view_mixin_test',
+ 'test/mixins/common/widget_mixin_test',
'test/mixins/main/host/details/host_components/decommissionable_test',
'test/mixins/routers/redirections_test',
'test/mixins/wizard/addSeccurityConfigs_test',
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 52091c1..045333f 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -38,3 +38,4 @@ require('mixins/wizard/selectHost');
require('mixins/wizard/addSecurityConfigs');
require('mixins/wizard/wizard_menu_view');
require('mixins/common/configs/enhanced_configs');
+require('mixins/common/widget_mixin');
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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
new file mode 100644
index 0000000..1f90500
--- /dev/null
+++ b/ambari-web/app/mixins/common/widget_mixin.js
@@ -0,0 +1,179 @@
+/**
+ * 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.WidgetMixin = Ember.Mixin.create({
+
+ /**
+ * @type {RegExp}
+ * @const
+ */
+ EXPRESSION_REGEX: /\$\{([\w\.\+\-\*\/\(\)]*)\}/g,
+
+ /**
+ * @type {RegExp}
+ * @const
+ */
+ MATH_EXPRESSION_REGEX: /^[\d\+\-\*\/\(\)\.]+$/,
+
+ /**
+ * @type {RegExp}
+ * @const
+ */
+ VALUE_NAME_REGEX: /[\w\.]+/g,
+
+ /**
+ * common metrics container
+ * @type {Array}
+ */
+ metrics: [],
+
+ /**
+ * @type {boolean}
+ */
+ isLoaded: false,
+
+ /**
+ * @type {App.Widget}
+ * @default null
+ */
+ content: null,
+
+ /**
+ * load metrics
+ */
+ beforeRender: function () {
+ var requestData = this.getRequestData(this.get('content.metrics')),
+ request,
+ requestCounter = 0,
+ self = this;
+
+ for (var i in requestData) {
+ request = requestData[i];
+ requestCounter++;
+ if (request.host_component_criteria) {
+ this.getHostComponentMetrics(request).complete(function () {
+ requestCounter--;
+ if (requestCounter === 0) self.set('isLoaded', true);
+ });
+ } else {
+ this.getServiceComponentMetrics(request).complete(function () {
+ requestCounter--;
+ if (requestCounter === 0) self.set('isLoaded', true);
+ });
+ }
+ }
+ },
+
+ /**
+ * extract expressions
+ * Example:
+ * input: "${a/b} equal ${b+a}"
+ * expressions: ['a/b', 'b+a']
+ *
+ * @param {object} input
+ * @returns {Array}
+ */
+ extractExpressions: function (input) {
+ var pattern = this.get('EXPRESSION_REGEX'),
+ expressions = [],
+ match;
+
+ while (match = pattern.exec(input.value)) {
+ expressions.push(match[1]);
+ }
+ return expressions;
+ },
+
+ /**
+ * get data formatted for request
+ * @param {Array} metrics
+ */
+ getRequestData: function (metrics) {
+ var requestsData = {};
+
+ metrics.forEach(function (metric) {
+ var key = metric.service_name + '_' + metric.component_name + '_' + metric.host_component_criteria;
+ var requestMetric = $.extend({}, metric);
+
+ if (requestsData[key]) {
+ requestsData[key]["widget_ids"].push(requestMetric["widget_id"]);
+ } else {
+ requestMetric["widget_ids"] = [requestMetric["widget_id"]];
+ delete requestMetric["widget_id"];
+ requestsData[key] = requestMetric;
+ }
+ }, this);
+ return requestsData;
+ },
+
+ /**
+ * make GET call to server in order to fetch service-component metrics
+ * @param {object} request
+ * @returns {$.ajax}
+ */
+ getServiceComponentMetrics: function (request) {
+ return App.ajax.send({
+ name: 'widgets.serviceComponent.metrics.get',
+ sender: this,
+ data: {
+ serviceName: request.service_name,
+ componentName: request.component_name,
+ widgetIds: request.widget_ids.join(',')
+ },
+ success: 'getServiceComponentMetricsSuccessCallback'
+ });
+ },
+
+ getServiceComponentMetricsSuccessCallback: function (data, opt, params) {
+ var metrics = [];
+ var metricsData = data.metrics[params.serviceName.toLowerCase()];
+
+ this.get('content.metrics').forEach(function (_metric) {
+ if (Em.get(metricsData, _metric.name)) {
+ _metric.data = Em.get(metricsData, _metric.name);
+ this.get('metrics').pushObject(_metric);
+ }
+ }, this);
+ },
+
+ /**
+ * make GET call to server in order to fetch host-component metrics
+ * @param {object} request
+ * @returns {$.ajax}
+ */
+ getHostComponentMetrics: function (request) {
+ return App.ajax.send({
+ name: 'widgets.hostComponent.metrics.get',
+ sender: this,
+ data: {
+ serviceName: request.service_name,
+ componentName: request.component_name,
+ widgetIds: request.widget_ids.join(','),
+ hostComponentCriteria: 'host_components/HostRoles/' + request.host_component_criteria
+ },
+ success: 'getHostComponentMetricsSuccessCallback'
+ });
+ },
+
+ getHostComponentMetricsSuccessCallback: function () {
+ //TODO push data to metrics after response structure approved
+ }
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/ambari-web/app/models/widget.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/widget.js b/ambari-web/app/models/widget.js
index 3d0ddc7..bdbb527 100644
--- a/ambari-web/app/models/widget.js
+++ b/ambari-web/app/models/widget.js
@@ -57,6 +57,8 @@ App.Widget = DS.Model.extend({
switch (this.get('widgetType')) {
case 'GRAPH':
return App.GraphWidgetView;
+ case 'NUMBER':
+ return App.TemplateWidgetView;
default:
return Em.View;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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
new file mode 100644
index 0000000..265e666
--- /dev/null
+++ b/ambari-web/app/styles/widget_layout.less
@@ -0,0 +1,39 @@
+/**
+ * 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 {
+ .template-widget {
+ height: 150px;
+ width: 90%;
+ .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;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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
new file mode 100644
index 0000000..fda71ea
--- /dev/null
+++ b/ambari-web/app/templates/common/widget/template_widget.hbs
@@ -0,0 +1,22 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+
+<div class="template-widget thumbnail">
+ <div class="caption title">{{view.title}}</div>
+ <div class="content"> {{view.value}}</div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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 b6a5e1d..e87ca6b 100644
--- a/ambari-web/app/templates/main/service/info/summary.hbs
+++ b/ambari-web/app/templates/main/service/info/summary.hbs
@@ -99,10 +99,12 @@
<div class="">
<table class="graphs">
{{#if App.supports.customizedWidgets}}
- <tr>
+ <tr id="widget_layout">
{{#each widget in controller.widgets}}
<td>
- {{view widget.viewClass contentBinding="widget"}}
+ <div class="widget">
+ {{view widget.viewClass contentBinding="widget"}}
+ </div>
</td>
{{/each}}
</tr>
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index a7719fc..cb121ec 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -63,6 +63,7 @@ require('views/common/configs/widgets/time_interval_spinner_view');
require('views/common/configs/widgets/toggle_config_widget_view');
require('views/common/configs/widgets/overrides/slider_config_widget_override_view');
require('views/common/configs/service_config_layout_tab_view');
+require('views/common/widget/template_widget_view');
require('views/common/filter_combobox');
require('views/common/filter_combo_cleanable');
require('views/common/table_view');
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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 a6cd420..c245622 100644
--- a/ambari-web/app/views/common/widget/graph_widget_view.js
+++ b/ambari-web/app/views/common/widget/graph_widget_view.js
@@ -18,7 +18,7 @@
var App = require('app');
-App.GraphWidgetView = App.ChartLinearTimeView.extend({
+App.GraphWidgetView = App.ChartLinearTimeView.extend(App.WidgetMixin, {
/**
* @type {string}
@@ -42,22 +42,10 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
}.property('properties.graph_type'),
/**
- * @type {RegExp}
- * @const
- */
- EXPRESSION_REGEX: /\$\{([\w\.\+\-\*\/\(\)]*)\}/g,
-
- /**
- * @type {RegExp}
- * @const
- */
- MATH_EXPRESSION_REGEX: /^[\d\+\-\*\/\(\)\.]+$/,
-
- /**
- * @type {RegExp}
- * @const
+ * common metrics container
+ * @type {Array}
*/
- VALUE_NAME_REGEX: /[\w\.]+/g,
+ metrics: [],
/**
* value in ms
@@ -71,49 +59,6 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
*/
timeStep: 15,
- /**
- * common metrics container
- * @type {Array}
- */
- metrics: [],
-
- /**
- * @type {boolean}
- */
- isLoaded: false,
-
- /**
- * @type {App.Widget}
- * @default null
- */
- content: null,
-
- /**
- * load metrics
- */
- beforeRender: function () {
- var requestData = this.getRequestData(this.get('content.metrics')),
- request,
- requestCounter = 0,
- self = this;
-
- for (var i in requestData) {
- request = requestData[i];
- requestCounter++;
- if (request.host_component_criteria) {
- this.getHostComponentMetrics(request).complete(function () {
- requestCounter--;
- if (requestCounter === 0) self.set('isLoaded', true);
- });
- } else {
- this.getServiceComponentMetrics(request).complete(function () {
- requestCounter--;
- if (requestCounter === 0) self.set('isLoaded', true);
- });
- }
- }
- },
-
didInsertElement: Em.K,
transformToSeries: function (seriesData) {
@@ -131,7 +76,6 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
*/
calculateSeries: function () {
var metrics = this.get('metrics');
- var widgetType = this.get('content.widgetType');
var seriesData = [];
this.get('content.values').forEach(function (value) {
@@ -183,56 +127,6 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
},
/**
- * TODO should be used for simple type of widgets
- * @param expressions
- * @param metrics
- * @returns {object}
- *//*
- computeExpressions: function (expressions, metrics) {
- var result = {};
-
- expressions.forEach(function (_expression) {
- var validExpression = true;
- var value = "";
-
- //replace values with metrics data
- var beforeCompute = _expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
- if (metrics.someProperty('name', match)) {
- return metrics.findProperty('name', match).data;
- } else {
- validExpression = false;
- console.warn('Metrics not found to compute expression');
- }
- });
-
- if (validExpression) {
- //check for correct math expression
- validExpression = this.get('MATH_EXPRESSION_REGEX').test(beforeCompute);
- !validExpression && console.warn('Value is not correct mathematical expression');
- }
-
- result['${' + _expression + '}'] = (validExpression) ? Number(window.eval(beforeCompute)).toString() : value;
- }, this);
- return result;
- },*/
-
- /**
- * extract expressions
- * @param {object} value
- * @returns {Array}
- */
- extractExpressions: function (value) {
- var pattern = this.get('EXPRESSION_REGEX'),
- expressions = [],
- match;
-
- while (match = pattern.exec(value.value)) {
- expressions.push(match[1]);
- }
- return expressions;
- },
-
- /**
* make GET call to server in order to fetch service-component metrics
* @param {object} request
* @returns {$.ajax}
@@ -250,18 +144,6 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
});
},
- getServiceComponentMetricsSuccessCallback: function (data, opt, params) {
- var metrics = [];
- var metricsData = data.metrics[params.serviceName.toLowerCase()];
-
- this.get('content.metrics').forEach(function (_metric) {
- if (Em.get(metricsData, _metric.name)) {
- _metric.data = Em.get(metricsData, _metric.name);
- this.get('metrics').pushObject(_metric);
- }
- }, this);
- },
-
/**
* make GET call to server in order to fetch host-component metrics
* @param {object} request
@@ -281,31 +163,6 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
});
},
- getHostComponentMetricsSuccessCallback: function () {
- //TODO push data to metrics after response structure approved
- },
-
- /**
- * get data formatted for request
- * @param {Array} metrics
- */
- getRequestData: function (metrics) {
- var requestsData = {};
-
- metrics.forEach(function (metric) {
- var key = metric.service_name + '_' + metric.component_name + '_' + metric.host_component_criteria;
-
- if (requestsData[key]) {
- requestsData[key]["widget_ids"].push(metric["widget_id"]);
- } else {
- metric["widget_ids"] = [metric["widget_id"]];
- delete metric["widget_id"];
- requestsData[key] = metric;
- }
- }, this);
- return requestsData;
- },
-
/**
* add time properties
* @param {Array} widgetIds
@@ -323,4 +180,4 @@ App.GraphWidgetView = App.ChartLinearTimeView.extend({
return result;
}
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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
new file mode 100644
index 0000000..580b92a
--- /dev/null
+++ b/ambari-web/app/views/common/widget/template_widget_view.js
@@ -0,0 +1,96 @@
+/**
+ * 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.TemplateWidgetView = Em.View.extend(App.WidgetMixin, {
+ templateName: require('templates/common/widget/template_widget'),
+
+ /**
+ * @type {string}
+ */
+ title: '',
+
+ /**
+ * @type {string}
+ */
+ value: '',
+
+ /**
+ * common metrics container
+ * @type {Array}
+ */
+ metrics: [],
+
+ drawWidget: function () {
+ if (this.get('isLoaded')) {
+ this.calculateValues();
+ this.set('value', this.get('content.values')[0].computedValue);
+ this.set('title', this.get('content.values')[0].name);
+ }
+ }.observes('isLoaded'),
+
+ /**
+ * calculate series datasets for graph widgets
+ */
+ calculateValues: function () {
+ var metrics = this.get('metrics');
+ var displayUnit = this.get('content.properties.display_unit');
+
+ 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');
+ });
+ }, this);
+ },
+
+ /**
+ * compute expression
+ * @param expressions
+ * @param metrics
+ * @returns {object}
+ */
+ computeExpression: function (expressions, metrics) {
+ var result = {};
+
+ expressions.forEach(function (_expression) {
+ var validExpression = true;
+ var value = "";
+
+ //replace values with metrics data
+ var beforeCompute = _expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
+ if (metrics.someProperty('name', match)) {
+ return metrics.findProperty('name', match).data;
+ } else {
+ validExpression = false;
+ console.warn('Metrics not found to compute expression');
+ }
+ });
+
+ if (validExpression) {
+ //check for correct math expression
+ validExpression = this.get('MATH_EXPRESSION_REGEX').test(beforeCompute);
+ !validExpression && console.warn('Value is not correct mathematical expression');
+ }
+
+ result['${' + _expression + '}'] = (validExpression) ? Number(window.eval(beforeCompute)).toString() : value;
+ }, this);
+ return result;
+ }
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/bfb586d8/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
new file mode 100644
index 0000000..6b78769
--- /dev/null
+++ b/ambari-web/test/mixins/common/widget_mixin_test.js
@@ -0,0 +1,238 @@
+/**
+ * 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');
+
+describe('App.WidgetMixin', function() {
+ var mixinClass = Em.Object.extend(App.WidgetMixin, {metrics: [], content: {}});
+
+ describe('#beforeRender()', function () {
+ var mixinObject = mixinClass.create();
+ beforeEach(function () {
+ this.mock = sinon.stub(mixinObject, 'getRequestData');
+ sinon.stub(mixinObject, 'getHostComponentMetrics').returns({complete: function(callback){
+ callback();
+ }});
+ sinon.stub(mixinObject, 'getServiceComponentMetrics').returns({complete: function(callback){
+ callback();
+ }});
+ });
+ afterEach(function () {
+ this.mock.restore();
+ mixinObject.getHostComponentMetrics.restore();
+ mixinObject.getServiceComponentMetrics.restore();
+ });
+ it('has host_component_criteria', function () {
+ this.mock.returns({'key1': {host_component_criteria: 'criteria'}});
+ mixinObject.set('isLoaded', false);
+ mixinObject.beforeRender();
+
+ expect(mixinObject.getHostComponentMetrics.calledWith({host_component_criteria: 'criteria'})).to.be.true;
+ expect(mixinObject.get('isLoaded')).to.be.true;
+ });
+ it('host_component_criteria is absent', function () {
+ this.mock.returns({'key1': {}});
+ mixinObject.set('isLoaded', false);
+ mixinObject.beforeRender();
+
+ expect(mixinObject.getServiceComponentMetrics.calledWith({})).to.be.true;
+ expect(mixinObject.get('isLoaded')).to.be.true;
+ });
+ });
+
+ describe("#extractExpressions()", function() {
+ var mixinObject = mixinClass.create();
+ var testCases = [
+ {
+ data: '',
+ result: []
+ },
+ {
+ data: 'text',
+ result: []
+ },
+ {
+ data: 'text${a}',
+ result: ['a']
+ },
+ {
+ data: 'text${a} - ${a.b}',
+ result: ['a', 'a.b']
+ },
+ {
+ data: '${o.a-(b+4)/cc*tt}',
+ result: ['o.a-(b+4)/cc*tt']
+ }
+ ];
+ testCases.forEach(function (test) {
+ it('input: ' + test.data, function () {
+ var input = {value: test.data};
+ expect(mixinObject.extractExpressions(input)).to.eql(test.result);
+ });
+ });
+ });
+
+ describe("#getRequestData()", function() {
+ var mixinObject = mixinClass.create();
+ it("", function() {
+ var data = [
+ {
+ "name": "regionserver.Server.percentFilesLocal",
+ "widget_id": "metrics/hbase/regionserver/percentFilesLocal",
+ "service_name": "HBASE",
+ "component_name": "HBASE_REGIONSERVER"
+ },
+ {
+ "name": "regionserver.Server.percentFilesLocal2",
+ "widget_id": "w2",
+ "service_name": "HBASE",
+ "component_name": "HBASE_REGIONSERVER"
+ },
+ {
+ "name": "regionserver.Server.percentFilesLocal",
+ "widget_id": "metrics/hbase/regionserver/percentFilesLocal",
+ "service_name": "HBASE",
+ "component_name": "HBASE_REGIONSERVER",
+ "host_component_criteria": 'c1'
+ },
+ {
+ "name": "regionserver.Server.percentFilesLocal",
+ "widget_id": "metrics/hbase/regionserver/percentFilesLocal",
+ "service_name": "HDFS",
+ "component_name": "DATANODE",
+ "host_component_criteria": 'c1'
+ }
+ ];
+
+ expect(mixinObject.getRequestData(data)).to.eql({
+ "HBASE_HBASE_REGIONSERVER_undefined": {
+ "name": "regionserver.Server.percentFilesLocal",
+ "service_name": "HBASE",
+ "component_name": "HBASE_REGIONSERVER",
+ "widget_ids": [
+ "metrics/hbase/regionserver/percentFilesLocal",
+ "w2"
+ ]
+ },
+ "HBASE_HBASE_REGIONSERVER_c1": {
+ "name": "regionserver.Server.percentFilesLocal",
+ "service_name": "HBASE",
+ "component_name": "HBASE_REGIONSERVER",
+ "host_component_criteria": "c1",
+ "widget_ids": [
+ "metrics/hbase/regionserver/percentFilesLocal"
+ ]
+ },
+ "HDFS_DATANODE_c1": {
+ "name": "regionserver.Server.percentFilesLocal",
+ "service_name": "HDFS",
+ "component_name": "DATANODE",
+ "host_component_criteria": "c1",
+ "widget_ids": [
+ "metrics/hbase/regionserver/percentFilesLocal"
+ ]
+ }
+ });
+ });
+ });
+
+ describe("#getServiceComponentMetrics()", function () {
+ var mixinObject = mixinClass.create();
+ before(function () {
+ sinon.stub(App.ajax, 'send');
+ });
+ after(function () {
+ App.ajax.send.restore();
+ });
+ it("", function () {
+ var request = {
+ service_name: 'S1',
+ component_name: 'C1',
+ widget_ids: ['w1', 'w2']
+ };
+ mixinObject.getServiceComponentMetrics(request);
+ expect(App.ajax.send.getCall(0).args[0]).to.eql({
+ name: 'widgets.serviceComponent.metrics.get',
+ sender: mixinObject,
+ data: {
+ serviceName: 'S1',
+ componentName: 'C1',
+ widgetIds: 'w1,w2'
+ },
+ success: 'getServiceComponentMetricsSuccessCallback'
+ })
+ });
+ });
+
+ describe("#getServiceComponentMetricsSuccessCallback()", function() {
+ var mixinObject = mixinClass.create();
+
+ it("", function() {
+ var data = {
+ metrics: {
+ "hbase" : {
+ "ipc" : {
+ "IPC" : {
+ "numOpenConnections" : 11.5
+ }
+ }
+ }
+ }
+ };
+ mixinObject.set('content.metrics', [
+ {
+ name: 'ipc.IPC.numOpenConnections'
+ }
+ ]);
+ mixinObject.getServiceComponentMetricsSuccessCallback(data, {}, {serviceName: 'hbase'});
+ expect(mixinObject.get('metrics').findProperty('name', 'ipc.IPC.numOpenConnections').data).to.equal(11.5);
+ });
+ });
+
+ describe("#getHostComponentMetrics()", function () {
+ var mixinObject = mixinClass.create();
+ before(function () {
+ sinon.stub(App.ajax, 'send');
+ });
+ after(function () {
+ App.ajax.send.restore();
+ });
+ it("", function () {
+ var request = {
+ service_name: 'S1',
+ component_name: 'C1',
+ widget_ids: ['w1', 'w2'],
+ host_component_criteria: 'c1'
+ };
+ mixinObject.getHostComponentMetrics(request);
+ expect(App.ajax.send.getCall(0).args[0]).to.eql({
+ name: 'widgets.hostComponent.metrics.get',
+ sender: mixinObject,
+ data: {
+ serviceName: 'S1',
+ componentName: 'C1',
+ widgetIds: 'w1,w2',
+ hostComponentCriteria: 'host_components/HostRoles/c1'
+ },
+ success: 'getHostComponentMetricsSuccessCallback'
+ })
+ });
+ });
+
+});
+