diff --git a/src/kibana/plugins/metric_vis/index.js b/src/kibana/plugins/metric_vis/index.js
new file mode 100644
index 0000000000000..1fd0cfab5245a
--- /dev/null
+++ b/src/kibana/plugins/metric_vis/index.js
@@ -0,0 +1,5 @@
+define(function (require) {
+ require('registry/vis_types').register(function (Private) {
+ return Private(require('plugins/metric_vis/metric_vis'));
+ });
+});
\ No newline at end of file
diff --git a/src/kibana/plugins/metric_vis/metric_vis.html b/src/kibana/plugins/metric_vis/metric_vis.html
new file mode 100644
index 0000000000000..550395940fc01
--- /dev/null
+++ b/src/kibana/plugins/metric_vis/metric_vis.html
@@ -0,0 +1,4 @@
+
+
{{metric.value}}
+
{{metric.label}}
+
\ No newline at end of file
diff --git a/src/kibana/plugins/metric_vis/metric_vis.js b/src/kibana/plugins/metric_vis/metric_vis.js
new file mode 100644
index 0000000000000..9596655e78803
--- /dev/null
+++ b/src/kibana/plugins/metric_vis/metric_vis.js
@@ -0,0 +1,33 @@
+define(function (require) {
+ // we need to load the css ourselves
+ require('css!plugins/metric_vis/metric_vis.css');
+
+ // we also need to load the controller and used by the template
+ require('plugins/metric_vis/metric_vis_controller');
+
+ return function (Private) {
+ var TemplateVisType = Private(require('plugins/vis_types/template/template_vis_type'));
+ var Schemas = Private(require('plugins/vis_types/_schemas'));
+
+ // return the visType object, which kibana will use to display and configure new
+ // Vis object of this type.
+ return new TemplateVisType({
+ name: 'metric',
+ title: 'Metric',
+ icon: 'fa-calculator',
+ template: require('text!plugins/metric_vis/metric_vis.html'),
+ schemas: new Schemas([
+ {
+ group: 'metrics',
+ name: 'metric',
+ title: 'Metric',
+ min: 1,
+ max: 1,
+ defaults: [
+ { type: 'count', schema: 'metric' }
+ ]
+ }
+ ])
+ });
+ };
+});
\ No newline at end of file
diff --git a/src/kibana/plugins/metric_vis/metric_vis.less b/src/kibana/plugins/metric_vis/metric_vis.less
new file mode 100644
index 0000000000000..6bfa6610fd422
--- /dev/null
+++ b/src/kibana/plugins/metric_vis/metric_vis.less
@@ -0,0 +1,12 @@
+.metric-vis {
+ width: 100%;
+ text-align: center;
+
+ .metric-value {
+ font-size: 5em;
+ font-weight: bold;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+}
\ No newline at end of file
diff --git a/src/kibana/plugins/metric_vis/metric_vis_controller.js b/src/kibana/plugins/metric_vis/metric_vis_controller.js
new file mode 100644
index 0000000000000..2a954f80384b0
--- /dev/null
+++ b/src/kibana/plugins/metric_vis/metric_vis_controller.js
@@ -0,0 +1,23 @@
+define(function (require) {
+ // get the kibana/metric_vis module, and make sure that it requires the "kibana" module if it
+ // didn't already
+ var module = require('modules').get('kibana/metric_vis', ['kibana']);
+
+ module.controller('KbnMetricVisController', function ($scope) {
+ var metric = $scope.metric = {
+ label: null,
+ value: null
+ };
+
+ $scope.$watch('esResponse', function (resp) {
+ if (!resp) {
+ metric.label = metric.value = null;
+ } else {
+ var agg = $scope.vis.aggs[0];
+ metric.label = agg.makeLabel();
+ if (agg.type.name === 'count') metric.value = resp.hits.total;
+ else metric.value = resp.aggregations[agg.id].value;
+ }
+ });
+ });
+});
\ No newline at end of file
diff --git a/tasks/config/less.js b/tasks/config/less.js
index 8da0587a49557..15e259f2c653a 100644
--- a/tasks/config/less.js
+++ b/tasks/config/less.js
@@ -12,7 +12,8 @@ module.exports = {
'<%= plugins %>/visualize/styles/main.less',
'<%= plugins %>/visualize/styles/visualization.less',
'<%= plugins %>/visualize/styles/main.less',
- '<%= plugins %>/table_vis/table_vis.less'
+ '<%= plugins %>/table_vis/table_vis.less',
+ '<%= plugins %>/metric_vis/metric_vis.less'
],
expand: true,
ext: '.css',
diff --git a/test/unit/index.html b/test/unit/index.html
index 6211b5fbeb0c0..6b6f277546ab0 100644
--- a/test/unit/index.html
+++ b/test/unit/index.html
@@ -161,7 +161,8 @@
'specs/components/agg_response/tabify/tabify',
'specs/components/agg_table/index',
'specs/plugins/vis_types/index',
- 'specs/utils/slugify_id'
+ 'specs/utils/slugify_id',
+ 'specs/plugins/metric_vis/metric_vis_controller'
], function () {
bootstrap(kibana, sinon);
});
diff --git a/test/unit/specs/plugins/metric_vis/metric_vis_controller.js b/test/unit/specs/plugins/metric_vis/metric_vis_controller.js
new file mode 100644
index 0000000000000..b3157a80ce680
--- /dev/null
+++ b/test/unit/specs/plugins/metric_vis/metric_vis_controller.js
@@ -0,0 +1,61 @@
+define(function (require) {
+ var metricVis = {
+ aggs: [{
+ type: {name: 'count'},
+ schema: 'metric',
+ makeLabel: function () {
+ return 'Count of documents';
+ }
+ }]
+ };
+
+ var averageVis = {
+ aggs: [{
+ id: 'agg',
+ type: {name: 'average'},
+ schema: 'metric',
+ makeLabel: function () {
+ return 'Average bytes';
+ }
+ }]
+ };
+
+ describe('metric vis', function () {
+ var $scope;
+
+ beforeEach(module('kibana/metric_vis'));
+ beforeEach(inject(function ($rootScope, $controller) {
+ $scope = $rootScope.$new();
+ $controller('KbnMetricVisController', {$scope: $scope});
+ $scope.$digest();
+ }));
+
+ it('should set the metric', function () {
+ expect($scope).to.have.property('metric');
+ });
+
+ it('should set the metric label and value for count', function () {
+ expect($scope.metric.label).to.not.be.ok();
+ expect($scope.metric.value).to.not.be.ok();
+
+ $scope.vis = metricVis;
+ $scope.esResponse = {hits: {total: 4826}};
+ $scope.$digest();
+
+ expect($scope.metric.label).to.be('Count of documents');
+ expect($scope.metric.value).to.be($scope.esResponse.hits.total);
+ });
+
+ it('should set the metric value for average', function () {
+ expect($scope.metric.label).to.not.be.ok();
+ expect($scope.metric.value).to.not.be.ok();
+
+ $scope.vis = averageVis;
+ $scope.esResponse = {hits: {total: 4826}, aggregations: {agg: {value: 1234}}};
+ $scope.$digest();
+
+ expect($scope.metric.label).to.be('Average bytes');
+ expect($scope.metric.value).to.be($scope.esResponse.aggregations.agg.value);
+ });
+ });
+});
\ No newline at end of file