diff --git a/src/ui/public/agg_types/controls/sub_metric.html b/src/ui/public/agg_types/controls/sub_metric.html
new file mode 100644
index 0000000000000..88011451676be
--- /dev/null
+++ b/src/ui/public/agg_types/controls/sub_metric.html
@@ -0,0 +1,14 @@
+
diff --git a/src/ui/public/agg_types/index.js b/src/ui/public/agg_types/index.js
index 5f735860e0cf7..15d68fe4370b5 100644
--- a/src/ui/public/agg_types/index.js
+++ b/src/ui/public/agg_types/index.js
@@ -24,6 +24,7 @@ import AggTypesBucketsTermsProvider from 'ui/agg_types/buckets/terms';
import AggTypesBucketsFiltersProvider from 'ui/agg_types/buckets/filters';
import AggTypesBucketsSignificantTermsProvider from 'ui/agg_types/buckets/significant_terms';
import AggTypesBucketsGeoHashProvider from 'ui/agg_types/buckets/geo_hash';
+import AggTypesMetricsBucketSumProvider from 'ui/agg_types/metrics/bucket_sum';
export default function AggTypeService(Private) {
const aggs = {
@@ -42,7 +43,8 @@ export default function AggTypeService(Private) {
Private(AggTypesMetricsDerivativeProvider),
Private(AggTypesMetricsCumulativeSumProvider),
Private(AggTypesMetricsMovingAvgProvider),
- Private(AggTypesMetricsSerialDiffProvider)
+ Private(AggTypesMetricsSerialDiffProvider),
+ Private(AggTypesMetricsBucketSumProvider),
],
buckets: [
Private(AggTypesBucketsDateHistogramProvider),
diff --git a/src/ui/public/agg_types/metrics/bucket_sum.js b/src/ui/public/agg_types/metrics/bucket_sum.js
new file mode 100644
index 0000000000000..ea067e82e46b6
--- /dev/null
+++ b/src/ui/public/agg_types/metrics/bucket_sum.js
@@ -0,0 +1,18 @@
+import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
+import { makeNestedLabel } from './lib/make_nested_label';
+import SiblingPipelineAggHelperProvider from './lib/sibling_pipeline_agg_helper';
+
+
+export default function AggTypeMetricDerivativeProvider(Private) {
+ const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
+ const siblingPipelineHelper = Private(SiblingPipelineAggHelperProvider);
+
+ return new MetricAggType({
+ name: 'sum_bucket',
+ title: 'Bucket Sum',
+ makeLabel: agg => makeNestedLabel(agg, 'overall sum'),
+ params: [
+ ...siblingPipelineHelper.params()
+ ]
+ });
+}
diff --git a/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_controller.js b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_controller.js
new file mode 100644
index 0000000000000..4d08761826e0c
--- /dev/null
+++ b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_controller.js
@@ -0,0 +1,31 @@
+import safeMakeLabel from './safe_make_label';
+
+const siblingPipelineAggController = function (type) {
+ return function ($scope) {
+
+ $scope.aggType = type;
+ //$scope.aggParam = $scope.agg.params[type];
+ $scope.aggTitle = type === 'customMetric' ? 'Metric' : 'Bucket';
+ $scope.aggGroup = type === 'customMetric' ? 'metrics' : 'buckets';
+ $scope.safeMakeLabel = safeMakeLabel;
+
+ $scope.rejectAgg = function (agg) {
+ const invalidAggs = ['top_hits', 'percentiles', 'percentile_ranks', 'median', 'std_dev'];
+ return Boolean(invalidAggs.find(agg.type.name));
+ };
+
+ //$scope.$watch(`agg.params.${type}`, updateAgg);
+
+ function updateAgg() {
+ const agg = $scope.agg;
+ const params = agg.params;
+ const paramDef = agg.type.params.byName[type];
+
+ params[type] = params[type] || paramDef.makeAgg(agg);
+ }
+
+ updateAgg();
+ };
+};
+
+export { siblingPipelineAggController };
diff --git a/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.js b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.js
new file mode 100644
index 0000000000000..60b0e3d851cd1
--- /dev/null
+++ b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.js
@@ -0,0 +1,86 @@
+import _ from 'lodash';
+import VisAggConfigProvider from 'ui/vis/agg_config';
+import VisSchemasProvider from 'ui/vis/schemas';
+
+import { siblingPipelineAggController } from './sibling_pipeline_agg_controller';
+import { siblingPipelineAggWritter } from './sibling_pipeline_agg_writter';
+import metricAggTemplate from 'ui/agg_types/controls/sub_metric.html';
+
+const SiblingPipelineAggHelperProvider = function (Private) {
+
+ const AggConfig = Private(VisAggConfigProvider);
+ const Schemas = Private(VisSchemasProvider);
+
+ const metricAggFilter = ['!top_hits', '!percentiles', '!percentile_ranks', '!median', '!std_dev'];
+ const metricAggSchema = (new Schemas([
+ {
+ group: 'none',
+ name: 'metricAgg',
+ title: 'Metric Agg',
+ aggFilter: metricAggFilter
+ }
+ ])).all[0];
+
+ const bucketAggFilter = [];
+ const bucketAggSchema = (new Schemas([
+ {
+ group: 'none',
+ title: 'Bucket Agg',
+ name: 'bucketAgg',
+ aggFilter: bucketAggFilter
+ }
+ ])).all[0];
+
+ return {
+ params: function () {
+ return [
+ {
+ name: 'customBucket',
+ type: AggConfig,
+ default: null,
+ serialize: function (customMetric) {
+ return customMetric.toJSON();
+ },
+ deserialize: function (state, agg) {
+ return this.makeAgg(agg, state);
+ },
+ makeAgg: function (agg, state) {
+ state = state || {};
+ state.schema = bucketAggSchema;
+ const orderAgg = new AggConfig(agg.vis, state);
+ orderAgg.id = agg.id + '-bucket';
+ return orderAgg;
+ },
+ editor: metricAggTemplate,
+ controller: siblingPipelineAggController('customBucket'),
+ write: _.noop
+ },
+ {
+ name: 'customMetric',
+ type: AggConfig,
+ default: null,
+ serialize: function (customMetric) {
+ return customMetric.toJSON();
+ },
+ deserialize: function (state, agg) {
+ return this.makeAgg(agg, state);
+ },
+ makeAgg: function (agg, state) {
+ state = state || {};
+ state.schema = metricAggSchema;
+ const orderAgg = new AggConfig(agg.vis, state);
+ orderAgg.id = agg.id + '-metric';
+ return orderAgg;
+ },
+ editor: metricAggTemplate,
+ controller: siblingPipelineAggController('customMetric'),
+ write: siblingPipelineAggWritter
+ }
+ ];
+ }
+ };
+
+
+};
+
+export default SiblingPipelineAggHelperProvider;
diff --git a/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writter.js b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writter.js
new file mode 100644
index 0000000000000..2b7b51f64d059
--- /dev/null
+++ b/src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writter.js
@@ -0,0 +1,19 @@
+const siblingPipelineAggWritter = function (agg, output) {
+ if (!agg.params.customMetric) return;
+
+ const metricAgg = agg.params.customMetric;
+ const bucketAgg = agg.params.customBucket;
+
+ // if a bucket is selected, we must add this agg as a sibling to it, and add a metric to that bucket (or select one of its)
+ if (metricAgg.type.name !== 'count') {
+ bucketAgg.subAggs = (output.subAggs || []).concat(metricAgg);
+ output.params.buckets_path = `${bucketAgg.id}>${metricAgg.id}`;
+ } else {
+ output.params.buckets_path = bucketAgg.id + '>_count';
+ }
+
+ output.parentAggs = (output.parentAggs || []).concat(bucketAgg);
+
+};
+
+export { siblingPipelineAggWritter };