From 566e60dc7d29e493485ac9c43772fd1360bc213e Mon Sep 17 00:00:00 2001 From: Shelby Sturgis Date: Sat, 13 Dec 2014 01:33:12 +0100 Subject: [PATCH 001/142] adding error message for no results when vislib gets a data object with no data --- src/kibana/components/errors.js | 7 ++++++ src/kibana/components/vislib/lib/data.js | 6 +++-- .../components/vislib/lib/handler/handler.js | 25 ++++++++++++++++--- src/kibana/components/vislib/vis.js | 3 ++- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/kibana/components/errors.js b/src/kibana/components/errors.js index 877b30efc8137c..06aaf2bd70d6ab 100644 --- a/src/kibana/components/errors.js +++ b/src/kibana/components/errors.js @@ -214,5 +214,12 @@ define(function (require) { }; inherits(errors.NotEnoughData, KbnError); + errors.NoResults = function NoResults() { + KbnError.call(this, + 'No results found', + errors.NoResults); + }; + inherits(errors.NoResults, KbnError); + return errors; }); diff --git a/src/kibana/components/vislib/lib/data.js b/src/kibana/components/vislib/lib/data.js index 25aa81d4322ce0..b39c3411c0e75a 100644 --- a/src/kibana/components/vislib/lib/data.js +++ b/src/kibana/components/vislib/lib/data.js @@ -45,7 +45,7 @@ define(function (require) { } this.color = this.labels ? color(this.labels) : undefined; - + this._normalizeOrdered(); this._attr = _.defaults(attr || {}, { @@ -67,6 +67,8 @@ define(function (require) { type = 'series'; } else if (obj.slices) { type = 'slices'; + } else if (obj.geoJSON) { + type = 'goeJSON'; } }); @@ -459,7 +461,7 @@ define(function (require) { * series.rows is an array of arrays * each row is an array of values * last value in row array is bucket count - * + * * @method mapDataExtents * @param series {Array} Array of data objects * @returns {Array} min and max values diff --git a/src/kibana/components/vislib/lib/handler/handler.js b/src/kibana/components/vislib/lib/handler/handler.js index 8e7a94545308d8..6c9c7233495a82 100644 --- a/src/kibana/components/vislib/lib/handler/handler.js +++ b/src/kibana/components/vislib/lib/handler/handler.js @@ -1,6 +1,7 @@ define(function (require) { return function HandlerBaseClass(d3, Private) { var _ = require('lodash'); + var errors = require('errors'); var Data = Private(require('components/vislib/lib/data')); var Layout = Private(require('components/vislib/lib/layout/layout')); @@ -20,6 +21,7 @@ define(function (require) { } this.data = opts.data || new Data(vis.data, vis._attr); + this.vis = vis; this.el = vis.el; this.ChartClass = vis.ChartClass; @@ -49,6 +51,14 @@ define(function (require) { ], Boolean); } + Handler.prototype._validateData = function () { + var dataType = this.data.type; + + if (!dataType) { + throw new errors.NoResults(); + } + }; + /** * Renders the constructors that create the visualization, * including the chart constructor @@ -60,6 +70,7 @@ define(function (require) { var self = this; var charts = this.charts = []; + this._validateData(); this.renderArray.forEach(function (property) { if (typeof property.render === 'function') { property.render(); @@ -153,13 +164,21 @@ define(function (require) { Handler.prototype.error = function (message) { this.removeAll(this.el); - return d3.select(this.el) + var div = d3.select(this.el) .append('div') // class name needs `chart` in it for the polling checkSize function // to continuously call render on resize - .attr('class', 'visualize-error chart error') - .append('h4') + .attr('class', 'visualize-error chart error'); + + if (message === 'No results found') { + div.append('h2') + .html(''); + } + + div.append('h4') .text(message); + + return div; }; /** diff --git a/src/kibana/components/vislib/vis.js b/src/kibana/components/vislib/vis.js index 902583f1d56dce..b187132e8fdffa 100644 --- a/src/kibana/components/vislib/vis.js +++ b/src/kibana/components/vislib/vis.js @@ -80,7 +80,8 @@ define(function (require) { // Because we have to wait for the DOM element to initialize, we do not // want to throw an error when the DOM `el` is zero if (error instanceof errors.ContainerTooSmall || - error instanceof errors.NotEnoughData) { + error instanceof errors.NotEnoughData || + error instanceof errors.NoResults) { this.handler.error(error.message); } else { throw error; From 2d52936d9058eff0cb0eb2bc12cf57c05b7c5f03 Mon Sep 17 00:00:00 2001 From: Shelby Sturgis Date: Sat, 13 Dec 2014 16:33:04 +0100 Subject: [PATCH 002/142] adding YUI documentation --- src/kibana/components/errors.js | 3 +++ src/kibana/components/vislib/lib/handler/handler.js | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/kibana/components/errors.js b/src/kibana/components/errors.js index 06aaf2bd70d6ab..aafa2d64e1e40f 100644 --- a/src/kibana/components/errors.js +++ b/src/kibana/components/errors.js @@ -214,6 +214,9 @@ define(function (require) { }; inherits(errors.NotEnoughData, KbnError); + /** + * error thrown when no results are returned from an elasticsearch query + */ errors.NoResults = function NoResults() { KbnError.call(this, 'No results found', diff --git a/src/kibana/components/vislib/lib/handler/handler.js b/src/kibana/components/vislib/lib/handler/handler.js index 6c9c7233495a82..0a86664bc567e8 100644 --- a/src/kibana/components/vislib/lib/handler/handler.js +++ b/src/kibana/components/vislib/lib/handler/handler.js @@ -51,6 +51,13 @@ define(function (require) { ], Boolean); } + /** + * Validates whether data is actually present in the data object + * used to render the Vis. Throws a no results error if data is not + * present. + * + * @private + */ Handler.prototype._validateData = function () { var dataType = this.data.type; From 472d352ac5b5574ca6a8ed4176a337b878417e83 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Mon, 22 Dec 2014 18:21:22 -0700 Subject: [PATCH 003/142] set first field as default --- src/kibana/plugins/visualize/editor/agg.js | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/agg.js b/src/kibana/plugins/visualize/editor/agg.js index 62cf305b74643c..7dab2737b67b10 100644 --- a/src/kibana/plugins/visualize/editor/agg.js +++ b/src/kibana/plugins/visualize/editor/agg.js @@ -1,16 +1,17 @@ define(function (require) { require('modules') .get('app/visualize', ['ui.select']) - .directive('visEditorAgg', function ($compile, $parse, Private, Notifier) { + .directive('visEditorAgg', function ($compile, $parse, $filter, Private, Notifier) { + require('angular-ui-select'); + require('filters/field_type'); + require('filters/match_any'); + require('plugins/visualize/editor/agg_param'); + var _ = require('lodash'); var $ = require('jquery'); var aggTypes = Private(require('components/agg_types/index')); var aggSelectHtml = require('text!plugins/visualize/editor/agg_select.html'); var advancedToggleHtml = require('text!plugins/visualize/editor/advanced_toggle.html'); - require('angular-ui-select'); - - require('plugins/visualize/editor/agg_param'); - require('filters/match_any'); var notify = new Notifier({ location: 'visAggGroup' @@ -134,6 +135,20 @@ define(function (require) { attrs['ng-show'] = 'advancedToggled'; } + // default field selection to the first field in the list, if none is selected + if (param.name === 'field' && !$scope.agg.params.field) { + var fields = $scope.agg.vis.indexPattern.fields.raw; + var fieldTypes = param.filterFieldTypes; + + if (fieldTypes) { + fields = $filter('fieldType')(fields, fieldTypes); + fields = $filter('matchAny')(fields, [{ indexed: true }, { scripted: true }]); + fields = $filter('orderBy')(fields, ['type', 'name']); + + $scope.agg.params.field = fields[0]; + } + } + return $('') .attr(attrs) .append(param.editor) From 1fc75fedaa91681546b923c1e29cf9121af30623 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Tue, 23 Dec 2014 14:37:48 -0700 Subject: [PATCH 004/142] pass filtered fields into agg_param directive, remove isolate scope, select FieldAggParam value by default --- .../agg_types/controls/extended_bounds.html | 6 +-- .../components/agg_types/controls/field.html | 9 +--- .../agg_types/controls/filters.html | 8 ++-- .../agg_types/controls/interval.html | 6 +-- .../agg_types/controls/min_doc_count.html | 2 +- .../agg_types/controls/order_and_size.html | 6 +-- .../agg_types/controls/precision.html | 4 +- .../components/agg_types/controls/ranges.html | 6 +-- .../agg_types/controls/raw_json.html | 2 +- .../controls/regular_expression.html | 4 +- .../components/agg_types/controls/string.html | 2 +- src/kibana/plugins/visualize/editor/agg.js | 42 ++++++++++--------- .../plugins/visualize/editor/agg_param.js | 25 ++++++----- 13 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/kibana/components/agg_types/controls/extended_bounds.html b/src/kibana/components/agg_types/controls/extended_bounds.html index a1277b232f2c49..4a4da84e8dd52a 100644 --- a/src/kibana/components/agg_types/controls/extended_bounds.html +++ b/src/kibana/components/agg_types/controls/extended_bounds.html @@ -1,8 +1,8 @@ -
+
@@ -10,7 +10,7 @@
diff --git a/src/kibana/components/agg_types/controls/field.html b/src/kibana/components/agg_types/controls/field.html index fec759805def09..d8de0beaf1987e 100644 --- a/src/kibana/components/agg_types/controls/field.html +++ b/src/kibana/components/agg_types/controls/field.html @@ -6,12 +6,7 @@ class="form-control" name="field" required - ng-model="params.field" - ng-options=" - field as field.displayName group by field.type for field in aggConfig.vis.indexPattern.fields.raw - | fieldType: aggParam.filterFieldTypes - | matchAny: [{ indexed: true }, { scripted: true }] - | orderBy: ['type', 'name'] - "> + ng-model="agg.params.field" + ng-options="field as field.displayName group by field.type for field in indexedFields">
\ No newline at end of file diff --git a/src/kibana/components/agg_types/controls/filters.html b/src/kibana/components/agg_types/controls/filters.html index aa98f17642dae4..ca3feea0e14011 100644 --- a/src/kibana/components/agg_types/controls/filters.html +++ b/src/kibana/components/agg_types/controls/filters.html @@ -1,5 +1,5 @@
-
+
@@ -18,8 +18,8 @@
diff --git a/src/kibana/components/agg_types/controls/interval.html b/src/kibana/components/agg_types/controls/interval.html index 4d3add72870c71..dcd9d5a387efca 100644 --- a/src/kibana/components/agg_types/controls/interval.html +++ b/src/kibana/components/agg_types/controls/interval.html @@ -2,16 +2,16 @@
@@ -15,7 +15,7 @@ + ng-model="agg.params[aggParam.name].flags"> {{ $item }} {{ label }} diff --git a/src/kibana/components/agg_types/controls/string.html b/src/kibana/components/agg_types/controls/string.html index 0271f2a03951f3..3e14e72b01e872 100644 --- a/src/kibana/components/agg_types/controls/string.html +++ b/src/kibana/components/agg_types/controls/string.html @@ -1,6 +1,6 @@
- +
\ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg.js b/src/kibana/plugins/visualize/editor/agg.js index 7dab2737b67b10..67538d23052116 100644 --- a/src/kibana/plugins/visualize/editor/agg.js +++ b/src/kibana/plugins/visualize/editor/agg.js @@ -75,6 +75,9 @@ define(function (require) { $aggParamEditorsScope = null; } + // create child scope, used in the editors + $aggParamEditorsScope = $scope.$new(); + var agg = $scope.agg; var type = $scope.agg.type; @@ -102,6 +105,11 @@ define(function (require) { if (aggParam = getAggParamHTML(param, i)) { aggParamHTML[type].push(aggParam); } + + // if field param exists, compute allowed fields + if (param.name === 'field') { + $aggParamEditorsScope.indexedFields = getIndexedFields(param); + } }); // compile the paramEditors html elements @@ -112,7 +120,6 @@ define(function (require) { paramEditors = paramEditors.concat(aggParamHTML.advanced); } - $aggParamEditorsScope = $scope.$new(); $aggParamEditors = $(paramEditors).appendTo($editorContainer); $compile($aggParamEditors)($aggParamEditorsScope); }); @@ -124,37 +131,32 @@ define(function (require) { return; } - var attrs = { - 'agg-type': 'agg.type', - 'agg-config': 'agg', - 'params': 'agg.params' - }; + var attrs = {}; attrs['agg-param'] = 'agg.type.params[' + idx + ']'; if (param.advanced) { attrs['ng-show'] = 'advancedToggled'; } - // default field selection to the first field in the list, if none is selected - if (param.name === 'field' && !$scope.agg.params.field) { - var fields = $scope.agg.vis.indexPattern.fields.raw; - var fieldTypes = param.filterFieldTypes; - - if (fieldTypes) { - fields = $filter('fieldType')(fields, fieldTypes); - fields = $filter('matchAny')(fields, [{ indexed: true }, { scripted: true }]); - fields = $filter('orderBy')(fields, ['type', 'name']); - - $scope.agg.params.field = fields[0]; - } - } - return $('') .attr(attrs) .append(param.editor) .get(0); } + function getIndexedFields(param) { + var fields = $scope.agg.vis.indexPattern.fields.raw; + var fieldTypes = param.filterFieldTypes; + + if (fieldTypes) { + fields = $filter('fieldType')(fields, fieldTypes); + fields = $filter('matchAny')(fields, [{ indexed: true }, { scripted: true }]); + fields = $filter('orderBy')(fields, ['type', 'name']); + } + + return fields; + } + // generic child scope creation, for both schema and agg function editorScope() { var $editorScope = $scope.$new(); diff --git a/src/kibana/plugins/visualize/editor/agg_param.js b/src/kibana/plugins/visualize/editor/agg_param.js index 1ac37e52cf13a0..63b17142adcff1 100644 --- a/src/kibana/plugins/visualize/editor/agg_param.js +++ b/src/kibana/plugins/visualize/editor/agg_param.js @@ -3,27 +3,32 @@ define(function (require) { require('modules') .get('app/visualize') - .directive('visAggParamEditor', function (config) { + .directive('visAggParamEditor', function (config, $parse, Private) { + var FieldAggParam = Private(require('components/agg_types/param_types/field')); + return { restrict: 'E', - scope: { - aggType: '=', - aggConfig: '=', - aggParam: '=', - params: '=' - }, - template: function ($el, attr) { + scope: true, + template: function ($el) { return $el.html(); }, - link: function ($scope) { + link: function ($scope, $el, attr) { + $scope.aggParam = $parse(attr.aggParam)($scope); $scope.config = config; $scope.optionEnabled = function (option) { if (option && _.isFunction(option.enabled)) { - return option.enabled($scope.aggConfig); + return option.enabled($scope.agg); } return true; }; + + // set default value on field agg params + if ($scope.aggParam instanceof FieldAggParam) { + if (!$scope.agg.params[$scope.aggParam.name]) { + $scope.agg.params[$scope.aggParam.name] = $scope.indexedFields[0]; + } + } } }; }); From ce7dc1309f917f3f546aa05ea8cdba1620f8ce92 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Tue, 23 Dec 2014 15:11:06 -0700 Subject: [PATCH 005/142] aggType -> agg.type, not agg --- src/kibana/components/agg_types/controls/order_and_size.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/agg_types/controls/order_and_size.html b/src/kibana/components/agg_types/controls/order_and_size.html index 613a9ca837b294..8a9a81bf60079d 100644 --- a/src/kibana/components/agg_types/controls/order_and_size.html +++ b/src/kibana/components/agg_types/controls/order_and_size.html @@ -1,5 +1,5 @@
-
+
+
\ No newline at end of file diff --git a/src/kibana/components/agg_types/index.js b/src/kibana/components/agg_types/index.js index 0e1ca5b5a4a614..82d4703aae2716 100644 --- a/src/kibana/components/agg_types/index.js +++ b/src/kibana/components/agg_types/index.js @@ -9,7 +9,8 @@ define(function (require) { Private(require('components/agg_types/metrics/sum')), Private(require('components/agg_types/metrics/min')), Private(require('components/agg_types/metrics/max')), - Private(require('components/agg_types/metrics/cardinality')) + Private(require('components/agg_types/metrics/cardinality')), + Private(require('components/agg_types/metrics/percentiles')) ], buckets: [ Private(require('components/agg_types/buckets/date_histogram')), diff --git a/src/kibana/components/agg_types/metrics/_get_value_agg_config.js b/src/kibana/components/agg_types/metrics/_get_value_agg_config.js new file mode 100644 index 00000000000000..da6e591046731b --- /dev/null +++ b/src/kibana/components/agg_types/metrics/_get_value_agg_config.js @@ -0,0 +1,45 @@ +define(function (require) { + return function ValueAggConfigProvider() { + var _ = require('lodash'); + + /** + * Get the ValueAggConfig class for an aggConfig, + * which might be cached on the aggConfig or created. + * + * @param {AggConfig} agg - the AggConfig the VAC should inherit from + * @param {object} props - properties that the VAC should have + * @return {Constructor} - a constructor for VAC objects that will inherit the aggConfig + */ + return function getValueConfigClass(agg, props) { + if (agg.$$_ValueAggConfigClass) { + return agg.$$_ValueAggConfigClass; + } else { + return (agg.$$_ValueAggConfigClass = create(agg, props)); + } + }; + + function create(parentAgg, props) { + + /** + * AggConfig "wrapper" for multi-value metric aggs which + * need to modify AggConfig behavior for each value produced. + * + * @param {string|number} key - the key or index that identifies + * this part of the multi-value + */ + function ValueAggConfig(key) { + this.key = key; + this.parentId = this.id; + this.id = this.parentId + '$$' + key; + } + + ValueAggConfig.prototype = Object.create(parentAgg, { + constructor: ValueAggConfig + }); + + _.assign(ValueAggConfig.prototype, props); + + return ValueAggConfig; + } + }; +}); \ No newline at end of file diff --git a/src/kibana/components/agg_types/metrics/percentiles.js b/src/kibana/components/agg_types/metrics/percentiles.js index 67af5277055f14..9fb996f38dde91 100644 --- a/src/kibana/components/agg_types/metrics/percentiles.js +++ b/src/kibana/components/agg_types/metrics/percentiles.js @@ -1,12 +1,21 @@ define(function (require) { return function AggTypeMetricPercentilesProvider(Private) { - var AggType = Private(require('components/agg_types/_agg_type')); + var _ = require('lodash'); - return new AggType({ + var MetricAggType = Private(require('components/agg_types/metrics/_metric_agg_type')); + var getValueAggConfig = Private(require('components/agg_types/metrics/_get_value_agg_config')); + + var valueProps = { + makeLabel: function () { + return this.key + 'th percentile of ' + this.fieldDisplayName(); + } + }; + + return new MetricAggType({ name: 'percentiles', title: 'Percentiles', - makeLabel: function (aggConfig) { - return 'Percentiles of ' + aggConfig.fieldDisplayName(); + makeLabel: function (agg) { + return 'Percentiles of ' + agg.fieldDisplayName(); }, params: [ { @@ -14,9 +23,23 @@ define(function (require) { filterFieldTypes: 'number' }, { - name: 'percents' + name: 'percents', + editor: require('text!components/agg_types/controls/percents.html'), + default: [1, 5, 25, 50, 75, 95, 99] } - ] + ], + getReplacementAggs: function (agg) { + var ValueAggConfig = getValueAggConfig(agg, valueProps); + + return agg.params.percents.map(function (percent) { + return new ValueAggConfig(percent); + }); + }, + getValue: function (agg, bucket) { + return _.find(bucket[agg.parentId].values, function (value, key) { + return agg.key === parseFloat(key); + }); + } }); }; }); \ No newline at end of file From feb0d1388a8f532ad5f7965a52920193c8c30ace Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Tue, 30 Dec 2014 01:10:14 -0700 Subject: [PATCH 012/142] switch to pecent-list --- src/kibana/components/agg_types/controls/percents.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/agg_types/controls/percents.html b/src/kibana/components/agg_types/controls/percents.html index b7365ebc98abd4..eba912dfc2fb07 100644 --- a/src/kibana/components/agg_types/controls/percents.html +++ b/src/kibana/components/agg_types/controls/percents.html @@ -2,7 +2,7 @@
\ No newline at end of file From 4b14f0c152e35cc2ade200b341a72e7d8126ebe3 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Tue, 30 Dec 2014 01:11:53 -0700 Subject: [PATCH 013/142] [aggTypes/percentiles] use ordinalSuffix util for better labels --- src/kibana/components/agg_types/metrics/percentiles.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/agg_types/metrics/percentiles.js b/src/kibana/components/agg_types/metrics/percentiles.js index 9fb996f38dde91..e6c101a9a2157b 100644 --- a/src/kibana/components/agg_types/metrics/percentiles.js +++ b/src/kibana/components/agg_types/metrics/percentiles.js @@ -4,10 +4,14 @@ define(function (require) { var MetricAggType = Private(require('components/agg_types/metrics/_metric_agg_type')); var getValueAggConfig = Private(require('components/agg_types/metrics/_get_value_agg_config')); + var ordinalSuffix = require('utils/ordinal_suffix'); + + require('components/agg_types/controls/_percent_list'); + var percentEditor = require('text!components/agg_types/controls/percents.html'); var valueProps = { makeLabel: function () { - return this.key + 'th percentile of ' + this.fieldDisplayName(); + return ordinalSuffix(this.key) + ' percentile of ' + this.fieldDisplayName(); } }; @@ -24,7 +28,7 @@ define(function (require) { }, { name: 'percents', - editor: require('text!components/agg_types/controls/percents.html'), + editor: percentEditor, default: [1, 5, 25, 50, 75, 95, 99] } ], From 18d6cb5fee02549a78dcdc972f4dfc1c1485b477 Mon Sep 17 00:00:00 2001 From: Shelby Sturgis Date: Tue, 30 Dec 2014 14:26:14 -0500 Subject: [PATCH 014/142] fixing css/html issues --- .../components/vislib/lib/handler/handler.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/kibana/components/vislib/lib/handler/handler.js b/src/kibana/components/vislib/lib/handler/handler.js index d78104b136c2b3..2a237da8450953 100644 --- a/src/kibana/components/vislib/lib/handler/handler.js +++ b/src/kibana/components/vislib/lib/handler/handler.js @@ -178,14 +178,18 @@ define(function (require) { .attr('class', 'visualize-error chart error'); if (message === 'No results found') { - div.append('h2') - .html(''); + div.append('div') + .attr('class', 'text-center visualize-error visualize-chart ng-scope') + .append('div').attr('class', 'item top') + .append('div').attr('class', 'item') + .append('h2').html('') + .append('h4').text(message); + + div.append('div').attr('class', 'item bottom'); + return div; } - div.append('h4') - .text(message); - - return div; + return div.append('h4').text(message); }; /** From 8ca08d60bd52e6ad68064b664ddb0dda2ee3adf2 Mon Sep 17 00:00:00 2001 From: mrapple Date: Tue, 30 Dec 2014 16:07:31 -0600 Subject: [PATCH 015/142] Fix copy/paste line breaks --- src/kibana/components/style_compile/style_compile.css.tmpl | 1 + test/unit/specs/components/style_compile/style_compile.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/kibana/components/style_compile/style_compile.css.tmpl b/src/kibana/components/style_compile/style_compile.css.tmpl index d640d6f61d4dc2..1f23c6fb57a067 100644 --- a/src/kibana/components/style_compile/style_compile.css.tmpl +++ b/src/kibana/components/style_compile/style_compile.css.tmpl @@ -1,5 +1,6 @@ .truncate-by-height { max-height: <%= truncateMaxHeight %>; + display: inline-block; } .truncate-by-height::before { top: <%= truncateGradientTop %>; diff --git a/test/unit/specs/components/style_compile/style_compile.js b/test/unit/specs/components/style_compile/style_compile.js index 1b00489a8527fa..789d96e3382214 100644 --- a/test/unit/specs/components/style_compile/style_compile.js +++ b/test/unit/specs/components/style_compile/style_compile.js @@ -19,6 +19,7 @@ define(function (require) { expect($style.html().trim()).to.be([ '.truncate-by-height {', ' max-height: none;', + ' display: inline-block;', '}', '.truncate-by-height::before {', ' top: -15px;', @@ -30,6 +31,7 @@ define(function (require) { expect($style.html().trim()).to.be([ '.truncate-by-height {', ' max-height: 15px !important;', + ' display: inline-block;', '}', '.truncate-by-height::before {', ' top: 0px;', From eb5f7bac9adc259b566a5095da62178fc8c518de Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 2 Jan 2015 14:02:06 -0700 Subject: [PATCH 016/142] [aggType/aggParams] choose AggParam classes by type --- .../components/agg_types/_agg_params.js | 59 ++++++------------- src/kibana/components/agg_types/_agg_type.js | 13 +++- src/kibana/factories/base_object.js | 9 +-- 3 files changed, 32 insertions(+), 49 deletions(-) diff --git a/src/kibana/components/agg_types/_agg_params.js b/src/kibana/components/agg_types/_agg_params.js index d1d2f86a337538..79ae567ff5ea9d 100644 --- a/src/kibana/components/agg_types/_agg_params.js +++ b/src/kibana/components/agg_types/_agg_params.js @@ -4,19 +4,21 @@ define(function (require) { var _ = require('lodash'); var IndexedArray = require('utils/indexed_array/index'); - var BaseAggParam = Private(require('components/agg_types/param_types/base')); - var FieldAggParam = Private(require('components/agg_types/param_types/field')); - var OptionedAggParam = Private(require('components/agg_types/param_types/optioned')); - var RegexAggParam = Private(require('components/agg_types/param_types/regex')); - var StringAggParam = Private(require('components/agg_types/param_types/string')); - var RawJSONAggParam = Private(require('components/agg_types/param_types/raw_json')); + var paramTypeMap = { + field: Private(require('components/agg_types/param_types/field')), + optioned: Private(require('components/agg_types/param_types/optioned')), + regex: Private(require('components/agg_types/param_types/regex')), + string: Private(require('components/agg_types/param_types/string')), + raw_json: Private(require('components/agg_types/param_types/raw_json')), + _default: Private(require('components/agg_types/param_types/base')) + }; /** * Wraps a list of {{#crossLink "AggParam"}}{{/crossLink}} objects; owned by an {{#crossLink "AggType"}}{{/crossLink}} * * used to create: - * - `OptionedAggParam` – When the config has an array of `options: []` * - `FieldAggParam` – When the config has `name: "field"` + * - `*AggParam` – When the type matches something in the map above * - `BaseAggParam` – All other params * * @class AggParams @@ -26,42 +28,19 @@ define(function (require) { */ _(AggParams).inherits(IndexedArray); function AggParams(params) { - if (_.isPlainObject(params)) { - // convert the names: details format into details[].name - params = _.map(params, function (param, name) { - param.name = name; - return param; - }); - } - - // always append the raw JSON param - params.push({ - name: 'json', - type: 'json', - advanced: true - }); - AggParams.Super.call(this, { index: ['name'], - initialSet: params.map(function (param) { - if (param.name === 'field') { - return new FieldAggParam(param); - } - else if (param.type === 'optioned') { - return new OptionedAggParam(param); - } - else if (param.type === 'regex') { - return new RegexAggParam(param); - } - else if (param.type === 'string') { - return new StringAggParam(param); - } - else if (param.type === 'json') { - return new RawJSONAggParam(param); - } - else { - return new BaseAggParam(param); + initialSet: params.map(function (config) { + var type = config.name === 'field' ? config.name : config.type; + var Class = paramTypeMap[type] || paramTypeMap._default; + var param = new Class(config); + + // recursively init sub params + if (param.params && !(params.params instanceof AggParams)) { + param.params = new AggParams(param.params); } + + return param; }) }); } diff --git a/src/kibana/components/agg_types/_agg_type.js b/src/kibana/components/agg_types/_agg_type.js index 3531e31463821c..f1cba5c42bc050 100644 --- a/src/kibana/components/agg_types/_agg_type.js +++ b/src/kibana/components/agg_types/_agg_type.js @@ -79,9 +79,16 @@ define(function (require) { * @property params * @type {AggParams} */ - var params = this.params = config.params || []; - if (!(params instanceof AggParams)) { - params = this.params = new AggParams(params); + this.params = config.params || []; + if (!(this.params instanceof AggParams)) { + // always append the raw JSON param + this.params.push({ + name: 'json', + type: 'json', + advanced: true + }); + + this.params = new AggParams(this.params); } } diff --git a/src/kibana/factories/base_object.js b/src/kibana/factories/base_object.js index fbcc95a62def10..e040eefe5a247c 100644 --- a/src/kibana/factories/base_object.js +++ b/src/kibana/factories/base_object.js @@ -1,9 +1,8 @@ define(function (require) { - var _ = require('lodash'); - var rison = require('utils/rison'); - var angular = require('angular'); - return function BaseObjectProvider() { + var _ = require('lodash'); + var rison = require('utils/rison'); + var angular = require('angular'); function BaseObject(attributes) { // Set the attributes or default to an empty object @@ -40,7 +39,5 @@ define(function (require) { }; return BaseObject; - - }; }); From 9dd44321e2456e8e8c21472b9efad1975227473c Mon Sep 17 00:00:00 2001 From: lukasolson Date: Fri, 2 Jan 2015 14:50:42 -0700 Subject: [PATCH 017/142] Add markdown visualization (2182) --- bower.json | 3 +- .../components/visualize/visualize.html | 7 ++-- src/kibana/plugins/markdown_vis/index.js | 5 +++ .../plugins/markdown_vis/markdown_vis.html | 3 ++ .../plugins/markdown_vis/markdown_vis.js | 23 +++++++++++ .../plugins/markdown_vis/markdown_vis.less | 11 ++++++ .../markdown_vis/markdown_vis_controller.js | 12 ++++++ .../markdown_vis/markdown_vis_params.html | 5 +++ .../plugins/markdown_vis/metric_vis.html | 4 ++ src/kibana/plugins/markdown_vis/metric_vis.js | 39 +++++++++++++++++++ .../plugins/markdown_vis/metric_vis.less | 13 +++++++ .../markdown_vis/metric_vis_controller.js | 23 +++++++++++ .../markdown_vis/metric_vis_params.html | 4 ++ src/kibana/plugins/visualize/editor/editor.js | 2 +- .../plugins/visualize/editor/vis_options.js | 2 +- src/kibana/plugins/visualize/wizard/wizard.js | 1 + src/kibana/require.config.js | 6 ++- tasks/config/less.js | 3 +- .../markdown_vis/markdown_vis_controller.js | 25 ++++++++++++ 19 files changed, 182 insertions(+), 9 deletions(-) create mode 100644 src/kibana/plugins/markdown_vis/index.js create mode 100644 src/kibana/plugins/markdown_vis/markdown_vis.html create mode 100644 src/kibana/plugins/markdown_vis/markdown_vis.js create mode 100644 src/kibana/plugins/markdown_vis/markdown_vis.less create mode 100644 src/kibana/plugins/markdown_vis/markdown_vis_controller.js create mode 100644 src/kibana/plugins/markdown_vis/markdown_vis_params.html create mode 100644 src/kibana/plugins/markdown_vis/metric_vis.html create mode 100644 src/kibana/plugins/markdown_vis/metric_vis.js create mode 100644 src/kibana/plugins/markdown_vis/metric_vis.less create mode 100644 src/kibana/plugins/markdown_vis/metric_vis_controller.js create mode 100644 src/kibana/plugins/markdown_vis/metric_vis_params.html create mode 100644 test/unit/specs/plugins/markdown_vis/markdown_vis_controller.js diff --git a/bower.json b/bower.json index 621e43b79c019b..ca1e772735e24d 100644 --- a/bower.json +++ b/bower.json @@ -48,7 +48,8 @@ "require-css": "~0.1.2", "requirejs": "~2.1.10", "requirejs-text": "~2.0.10", - "lodash-deep": "spenceralger/lodash-deep#a2768a72d7" + "lodash-deep": "spenceralger/lodash-deep#a2768a72d7", + "marked": "~0.3.2" }, "devDependencies": {} } diff --git a/src/kibana/components/visualize/visualize.html b/src/kibana/components/visualize/visualize.html index b0d25a7791f7f6..9c9bf27dc3f3a5 100644 --- a/src/kibana/components/visualize/visualize.html +++ b/src/kibana/components/visualize/visualize.html @@ -1,4 +1,4 @@ -
@@ -7,7 +7,6 @@

No results found

- -
+
- + \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/index.js b/src/kibana/plugins/markdown_vis/index.js new file mode 100644 index 00000000000000..e3c521da51a64c --- /dev/null +++ b/src/kibana/plugins/markdown_vis/index.js @@ -0,0 +1,5 @@ +define(function (require) { + require('registry/vis_types').register(function (Private) { + return Private(require('plugins/markdown_vis/markdown_vis')); + }); +}); \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/markdown_vis.html b/src/kibana/plugins/markdown_vis/markdown_vis.html new file mode 100644 index 00000000000000..81940aae8de3f0 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/markdown_vis.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/markdown_vis.js b/src/kibana/plugins/markdown_vis/markdown_vis.js new file mode 100644 index 00000000000000..24a75cc020b5ae --- /dev/null +++ b/src/kibana/plugins/markdown_vis/markdown_vis.js @@ -0,0 +1,23 @@ +define(function (require) { + // we need to load the css ourselves + require('css!plugins/markdown_vis/markdown_vis.css'); + + // we also need to load the controller and used by the template + require('plugins/markdown_vis/markdown_vis_controller'); + + return function (Private) { + var TemplateVisType = Private(require('plugins/vis_types/template/template_vis_type')); + + // return the visType object, which kibana will use to display and configure new + // Vis object of this type. + return new TemplateVisType({ + name: 'markdown', + title: 'Markdown widget', + icon: 'fa-code', + template: require('text!plugins/markdown_vis/markdown_vis.html'), + params: { + editor: require('text!plugins/markdown_vis/markdown_vis_params.html') + } + }); + }; +}); \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/markdown_vis.less b/src/kibana/plugins/markdown_vis/markdown_vis.less new file mode 100644 index 00000000000000..3de6a50e07a500 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/markdown_vis.less @@ -0,0 +1,11 @@ +@import (reference) "../../styles/_mixins.less"; +@import (reference) "lesshat.less"; + +.markdown-vis { + padding: 1em; + width: 100%; +} + +.markdown-vis-options textarea { + font-family: monospace; +} \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/markdown_vis_controller.js b/src/kibana/plugins/markdown_vis/markdown_vis_controller.js new file mode 100644 index 00000000000000..c9036b65644665 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/markdown_vis_controller.js @@ -0,0 +1,12 @@ +define(function (require) { + var marked = require('marked'); + marked.setOptions({sanitize: true}); // Sanitize HTML tags + + var module = require('modules').get('kibana/markdown_vis', ['kibana']); + module.controller('KbnMarkdownVisController', function ($scope, $sce) { + $scope.$watch('vis.params.markdown', function (html) { + if (!html) return; + $scope.html = $sce.trustAsHtml(marked(html)); + }); + }); +}); \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/markdown_vis_params.html b/src/kibana/plugins/markdown_vis/markdown_vis_params.html new file mode 100644 index 00000000000000..cb953a6a22bf7e --- /dev/null +++ b/src/kibana/plugins/markdown_vis/markdown_vis_params.html @@ -0,0 +1,5 @@ +
+ + Help + +
\ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/metric_vis.html b/src/kibana/plugins/markdown_vis/metric_vis.html new file mode 100644 index 00000000000000..f2a592a0932c95 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/metric_vis.html @@ -0,0 +1,4 @@ +
+
{{metric.value}}
+
{{metric.label}}
+
\ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/metric_vis.js b/src/kibana/plugins/markdown_vis/metric_vis.js new file mode 100644 index 00000000000000..bfa785daff61ff --- /dev/null +++ b/src/kibana/plugins/markdown_vis/metric_vis.js @@ -0,0 +1,39 @@ +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'), + params: { + defaults: { + fontSize: 60 + }, + editor: require('text!plugins/metric_vis/metric_vis_params.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/markdown_vis/metric_vis.less b/src/kibana/plugins/markdown_vis/metric_vis.less new file mode 100644 index 00000000000000..2040a247376e71 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/metric_vis.less @@ -0,0 +1,13 @@ +@import (reference) "../../styles/_mixins.less"; +@import (reference) "lesshat.less"; + +.metric-vis { + text-align: center; + .flex-parent(); + .justify-content(center); + + .metric-value { + font-weight: bold; + .ellipsis(); + } +} \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/metric_vis_controller.js b/src/kibana/plugins/markdown_vis/metric_vis_controller.js new file mode 100644 index 00000000000000..2a954f80384b0a --- /dev/null +++ b/src/kibana/plugins/markdown_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/src/kibana/plugins/markdown_vis/metric_vis_params.html b/src/kibana/plugins/markdown_vis/metric_vis_params.html new file mode 100644 index 00000000000000..6ac1762c3b6bf1 --- /dev/null +++ b/src/kibana/plugins/markdown_vis/metric_vis_params.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/editor.js b/src/kibana/plugins/visualize/editor/editor.js index a0c69729d61d57..3d2b919d3acd16 100644 --- a/src/kibana/plugins/visualize/editor/editor.js +++ b/src/kibana/plugins/visualize/editor/editor.js @@ -15,7 +15,7 @@ define(function (require) { template: require('text!plugins/visualize/editor/editor.html'), resolve: { savedVis: function (savedVisualizations, courier, $route) { - if (!$route.current.params.indexPattern && !$route.current.params.savedSearchId) { + if (!$route.current.params.indexPattern && !$route.current.params.savedSearchId && $route.current.params.type !== 'markdown') { throw new Error('You must provide either an indexPattern or a savedSearchId'); } diff --git a/src/kibana/plugins/visualize/editor/vis_options.js b/src/kibana/plugins/visualize/editor/vis_options.js index 5c6e7381549861..eccb6a87aaf0cf 100644 --- a/src/kibana/plugins/visualize/editor/vis_options.js +++ b/src/kibana/plugins/visualize/editor/vis_options.js @@ -17,7 +17,7 @@ define(function (require) { var $editor = $compile($scope.vis.type.params.editor)($scope); $optionContainer.append($editor); - $scope.$watch('vis.type.schemas.length', function (len) { + $scope.$watch('vis.type.schemas.all.length', function (len) { $scope.alwaysShowOptions = len === 0; }); } diff --git a/src/kibana/plugins/visualize/wizard/wizard.js b/src/kibana/plugins/visualize/wizard/wizard.js index aeeb62001b7465..fe9d8a853d6350 100644 --- a/src/kibana/plugins/visualize/wizard/wizard.js +++ b/src/kibana/plugins/visualize/wizard/wizard.js @@ -24,6 +24,7 @@ define(function (require) { $scope.visTypes = Private(require('registry/vis_types')); $scope.visTypeUrl = function (visType) { + if (visType.name === 'markdown') return '#/visualize/create?type=markdown'; return '#/visualize/step/2?type=' + encodeURIComponent(visType.name); }; }); diff --git a/src/kibana/require.config.js b/src/kibana/require.config.js index 5bf43842d0d2cb..6f0d7b5cf38c90 100644 --- a/src/kibana/require.config.js +++ b/src/kibana/require.config.js @@ -33,7 +33,8 @@ require.config({ moment: 'bower_components/moment/moment', 'ng-clip': 'bower_components/ng-clip/src/ngClip', text: 'bower_components/requirejs-text/text', - zeroclipboard: 'bower_components/zeroclipboard/dist/ZeroClipboard' + zeroclipboard: 'bower_components/zeroclipboard/dist/ZeroClipboard', + marked: 'bower_components/marked/lib/marked' }, shim: { angular: { @@ -56,6 +57,9 @@ require.config({ }, leaflet: { deps: ['css!bower_components/leaflet/dist/leaflet.css'] + }, + marked: { + exports: 'marked' } }, waitSeconds: 60 diff --git a/tasks/config/less.js b/tasks/config/less.js index 15e259f2c653ae..21e9c640f9a286 100644 --- a/tasks/config/less.js +++ b/tasks/config/less.js @@ -13,7 +13,8 @@ module.exports = { '<%= plugins %>/visualize/styles/visualization.less', '<%= plugins %>/visualize/styles/main.less', '<%= plugins %>/table_vis/table_vis.less', - '<%= plugins %>/metric_vis/metric_vis.less' + '<%= plugins %>/metric_vis/metric_vis.less', + '<%= plugins %>/markdown_vis/markdown_vis.less' ], expand: true, ext: '.css', diff --git a/test/unit/specs/plugins/markdown_vis/markdown_vis_controller.js b/test/unit/specs/plugins/markdown_vis/markdown_vis_controller.js new file mode 100644 index 00000000000000..9b9797320029e3 --- /dev/null +++ b/test/unit/specs/plugins/markdown_vis/markdown_vis_controller.js @@ -0,0 +1,25 @@ +define(function (require) { + describe('markdown vis controller', function () { + var $scope, $el; + + beforeEach(module('kibana/markdown_vis')); + beforeEach(inject(function ($rootScope, $controller) { + $scope = $rootScope.$new(); + $controller('KbnMarkdownVisController', {$scope: $scope}); + $scope.$digest(); + })); + + it('should set html from markdown params', function () { + expect($scope).to.not.have.property('html'); + $scope.vis = { + params: { + markdown: 'This is a test of the [markdown](http://daringfireball.net/projects/markdown) vis.' + } + }; + $scope.$digest(); + + expect($scope).to.have.property('html'); + expect($scope.html.toString().indexOf(' Date: Fri, 2 Jan 2015 15:23:02 -0700 Subject: [PATCH 018/142] Use github flavored markdown by default --- src/kibana/plugins/markdown_vis/markdown_vis_controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kibana/plugins/markdown_vis/markdown_vis_controller.js b/src/kibana/plugins/markdown_vis/markdown_vis_controller.js index c9036b65644665..591d2f8c1c3521 100644 --- a/src/kibana/plugins/markdown_vis/markdown_vis_controller.js +++ b/src/kibana/plugins/markdown_vis/markdown_vis_controller.js @@ -1,6 +1,9 @@ define(function (require) { var marked = require('marked'); - marked.setOptions({sanitize: true}); // Sanitize HTML tags + marked.setOptions({ + gfm: true, // Github-flavored markdown + sanitize: true // Sanitize HTML tags + }); var module = require('modules').get('kibana/markdown_vis', ['kibana']); module.controller('KbnMarkdownVisController', function ($scope, $sce) { From 63e8fb8189f4be891be18c675150acc7f5257206 Mon Sep 17 00:00:00 2001 From: lukasolson Date: Fri, 2 Jan 2015 16:37:57 -0700 Subject: [PATCH 019/142] Remove files that were accidentally added --- .../plugins/markdown_vis/metric_vis.html | 4 -- src/kibana/plugins/markdown_vis/metric_vis.js | 39 ------------------- .../plugins/markdown_vis/metric_vis.less | 13 ------- .../markdown_vis/metric_vis_controller.js | 23 ----------- .../markdown_vis/metric_vis_params.html | 4 -- 5 files changed, 83 deletions(-) delete mode 100644 src/kibana/plugins/markdown_vis/metric_vis.html delete mode 100644 src/kibana/plugins/markdown_vis/metric_vis.js delete mode 100644 src/kibana/plugins/markdown_vis/metric_vis.less delete mode 100644 src/kibana/plugins/markdown_vis/metric_vis_controller.js delete mode 100644 src/kibana/plugins/markdown_vis/metric_vis_params.html diff --git a/src/kibana/plugins/markdown_vis/metric_vis.html b/src/kibana/plugins/markdown_vis/metric_vis.html deleted file mode 100644 index f2a592a0932c95..00000000000000 --- a/src/kibana/plugins/markdown_vis/metric_vis.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
{{metric.value}}
-
{{metric.label}}
-
\ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/metric_vis.js b/src/kibana/plugins/markdown_vis/metric_vis.js deleted file mode 100644 index bfa785daff61ff..00000000000000 --- a/src/kibana/plugins/markdown_vis/metric_vis.js +++ /dev/null @@ -1,39 +0,0 @@ -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'), - params: { - defaults: { - fontSize: 60 - }, - editor: require('text!plugins/metric_vis/metric_vis_params.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/markdown_vis/metric_vis.less b/src/kibana/plugins/markdown_vis/metric_vis.less deleted file mode 100644 index 2040a247376e71..00000000000000 --- a/src/kibana/plugins/markdown_vis/metric_vis.less +++ /dev/null @@ -1,13 +0,0 @@ -@import (reference) "../../styles/_mixins.less"; -@import (reference) "lesshat.less"; - -.metric-vis { - text-align: center; - .flex-parent(); - .justify-content(center); - - .metric-value { - font-weight: bold; - .ellipsis(); - } -} \ No newline at end of file diff --git a/src/kibana/plugins/markdown_vis/metric_vis_controller.js b/src/kibana/plugins/markdown_vis/metric_vis_controller.js deleted file mode 100644 index 2a954f80384b0a..00000000000000 --- a/src/kibana/plugins/markdown_vis/metric_vis_controller.js +++ /dev/null @@ -1,23 +0,0 @@ -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/src/kibana/plugins/markdown_vis/metric_vis_params.html b/src/kibana/plugins/markdown_vis/metric_vis_params.html deleted file mode 100644 index 6ac1762c3b6bf1..00000000000000 --- a/src/kibana/plugins/markdown_vis/metric_vis_params.html +++ /dev/null @@ -1,4 +0,0 @@ -
- - -
\ No newline at end of file From bf5964f661a91becf47ff703fd377d6e99ed1ce6 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sat, 3 Jan 2015 19:26:50 -0700 Subject: [PATCH 020/142] [courier/fetch] properly order search source history, and attach fetch params --- .../components/courier/fetch/_call_client.js | 10 +++++- .../courier/fetch/request/request.js | 3 +- .../components/courier/fetch/strategy/doc.js | 13 +++---- .../courier/fetch/strategy/search.js | 36 ++++++++----------- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/kibana/components/courier/fetch/_call_client.js b/src/kibana/components/courier/fetch/_call_client.js index 7df3d7a574d4d8..2ac51a3604b7d8 100644 --- a/src/kibana/components/courier/fetch/_call_client.js +++ b/src/kibana/components/courier/fetch/_call_client.js @@ -67,7 +67,15 @@ define(function (require) { // Now that all of THAT^^^ is out of the way, lets actually // call out to elasticsearch - Promise.resolve(strategy.convertReqsToBody(executable)) + Promise.map(executable, function (req) { + return Promise.try(req.getFetchParams, void 0, req) + .then(function (fetchParams) { + return (req.fetchParams = fetchParams); + }); + }) + .then(function (reqsFetchParams) { + return strategy.reqsFetchParamsToBody(reqsFetchParams); + }) .then(function (body) { // while the strategy was converting, our request was aborted if (esPromise === ABORTED) { diff --git a/src/kibana/components/courier/fetch/request/request.js b/src/kibana/components/courier/fetch/request/request.js index 61446941e6dc4a..61d940ca211455 100644 --- a/src/kibana/components/courier/fetch/request/request.js +++ b/src/kibana/components/courier/fetch/request/request.js @@ -37,7 +37,8 @@ define(function (require) { } if (source.history) { - source.history = _.first(source.history.concat(this), 20); + source.history.push(this); + source.history = _.last(source.history, 20); } }; diff --git a/src/kibana/components/courier/fetch/strategy/doc.js b/src/kibana/components/courier/fetch/strategy/doc.js index e222e6233238bf..005de6d252ab50 100644 --- a/src/kibana/components/courier/fetch/strategy/doc.js +++ b/src/kibana/components/courier/fetch/strategy/doc.js @@ -8,15 +8,10 @@ define(function (require) { * @param {array} requests - an array of flattened requests * @return {string} - the request body */ - convertReqsToBody: function (reqs) { - return Promise.map(reqs, function (req) { - return req.getFetchParams(); - }) - .then(function (reqsParams) { - return { - docs: reqsParams - }; - }); + reqsFetchParamsToBody: function (reqsFetchParams) { + return { + docs: reqsFetchParams + }; }, /** diff --git a/src/kibana/components/courier/fetch/strategy/search.js b/src/kibana/components/courier/fetch/strategy/search.js index 0e7df87a138bc8..384adca809ce3d 100644 --- a/src/kibana/components/courier/fetch/strategy/search.js +++ b/src/kibana/components/courier/fetch/strategy/search.js @@ -11,29 +11,23 @@ define(function (require) { * @param {array} requests - the requests to serialize * @return {string} - the request body */ - convertReqsToBody: function (reqs) { - return Promise.map(reqs, function (req) { - return req.getFetchParams(); - }) - .then(function (reqsParams) { - return reqsParams.map(function (reqParams) { - var indexList = reqParams.index; + reqsFetchParamsToBody: function (reqsFetchParams) { + return reqsFetchParams.map(function (fetchParams) { + var indexList = fetchParams.index; - if (_.isFunction(_.deepGet(indexList, 'toIndexList'))) { - var timeBounds = timefilter.getBounds(); - indexList = indexList.toIndexList(timeBounds.min, timeBounds.max); - } + if (_.isFunction(_.deepGet(indexList, 'toIndexList'))) { + var timeBounds = timefilter.getBounds(); + indexList = indexList.toIndexList(timeBounds.min, timeBounds.max); + } - return JSON.stringify({ - index: indexList, - type: reqParams.type, - ignore_unavailable: true - }) - + '\n' - + JSON.stringify(reqParams.body || {}); - - }).join('\n') + '\n'; - }); + return JSON.stringify({ + index: indexList, + type: fetchParams.type, + ignore_unavailable: true + }) + + '\n' + + JSON.stringify(fetchParams.body || {}); + }).join('\n') + '\n'; }, /** From 44f0dac2b60f88eb6dbe8356ee69179e66d72c0f Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sat, 3 Jan 2015 20:52:42 -0700 Subject: [PATCH 021/142] [mixins] added behavior support --- src/kibana/utils/_mixins_chainable.js | 31 ++++++++++++++++++++++++ src/kibana/utils/_mixins_notchainable.js | 17 ++++++------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/kibana/utils/_mixins_chainable.js b/src/kibana/utils/_mixins_chainable.js index 01404ce87d4352..6ed63550a6fddf 100644 --- a/src/kibana/utils/_mixins_chainable.js +++ b/src/kibana/utils/_mixins_chainable.js @@ -12,6 +12,37 @@ define(function (require) { var _ = require('lodash_src'); return { + /** + * Setup Class-like inheritance between two constructors. + * Exposes the Super class at SubClass.Super; + * + * @param {Constructor} Sub - The "Class" that should be extended + * @param {Constructor} Super - The parent "Class" + * @return {Constructor} - the sub argument; + */ + inherits: function (Sub, Super) { + Sub.prototype = Object.create(Super.prototype, { + constructor: { + value: Sub + }, + superConstructor: Sub.Super = Super + }); + return Sub; + }, + + /** + * Add a behavior to a Class, and track the behavior to enable _.hasBehavior + * + * @param {Constructor} Class - The "Class" that should be extended + * @param {object} behavior - The behavior that should be mixed into to the Class + * @return {Constructor} - Class; + */ + addBehavior: function (Class, behavior) { + Class.$$_behaviors = (Class.$$_behaviors || []).concat(behavior); + _.merge(Class.prototype, behavior); + return Class; + }, + /** * Remove an element at a specific index from an array * diff --git a/src/kibana/utils/_mixins_notchainable.js b/src/kibana/utils/_mixins_notchainable.js index 893e0f0884bb89..627b735eba4979 100644 --- a/src/kibana/utils/_mixins_notchainable.js +++ b/src/kibana/utils/_mixins_notchainable.js @@ -13,17 +13,16 @@ define(function (require) { return { /** - * Setup Class-like inheritance between two constructors. - * Exposes the Super class at SubClass.Super; + * Check if an object or class implements a behavior * - * @param {Constructor} Sub - The "Class" that should be extended - * @param {Constructor} Super - The parent "Class" - * @return {Constructor} - the sub argument; + * @param {Class|obj} instClass - Class or instance to test + * @param {behavior} behavior - behavior to test for + * @return {Boolean} */ - inherits: function (Sub, Super) { - Sub.prototype = _.create(Super.prototype, { 'constructor': Sub }); - Sub.Super = Super; - return Sub; + hasBehavior: function (instClass, behavior) { + if (_.isObject(instClass)) instClass = instClass.constructor; + if (!_.isFunction(instClass) || !behavior) return; + return _.contains(instClass.$$_behaviors, behavior); }, /** From 2965f3531286e93ec51406c5c15ca75112750a7b Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sat, 3 Jan 2015 19:27:27 -0700 Subject: [PATCH 022/142] [visualize/spy] fix the req and resp spies --- .../visualize/spy/_req_resp_stats.js | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/kibana/components/visualize/spy/_req_resp_stats.js b/src/kibana/components/visualize/spy/_req_resp_stats.js index 52d066c0f177fc..2f89221d76dfe2 100644 --- a/src/kibana/components/visualize/spy/_req_resp_stats.js +++ b/src/kibana/components/visualize/spy/_req_resp_stats.js @@ -19,29 +19,25 @@ define(function (require) { if (!$scope.searchSource) return; - var searchHistory = $scope.searchSource.history; - if (!searchHistory) return; + var req = $scope.entry = _.last(_.deepGet($scope, 'searchSource.history')); + if (!req) return; - var entry = $scope.entry = _.find(searchHistory, 'state'); - if (!entry) return; - - var state = entry.state; - var resp = entry.resp; + var resp = req.resp; var meta = []; if (resp && resp.took != null) meta.push(['Query Duration', resp.took + 'ms']); - if (entry && entry.ms != null) meta.push(['Request Duration', entry.ms + 'ms']); + if (req && req.ms != null) meta.push(['Request Duration', req.ms + 'ms']); if (resp && resp.hits) meta.push(['Hits', resp.hits.total]); - if (state.index) meta.push(['Index', state.index]); - if (state.type) meta.push(['Type', state.type]); - if (state.id) meta.push(['Id', state.id]); + if (req.fetchParams.index) meta.push(['Index', req.fetchParams.index]); + if (req.fetchParams.type) meta.push(['Type', req.fetchParams.type]); + if (req.fetchParams.id) meta.push(['Id', req.fetchParams.id]); $scope.history = { meta: meta, - req: state.body, - resp: entry.resp, - complete: entry.complete + req: req.fetchParams.body, + resp: req.resp, + complete: req.complete }; }); }; From 33f4bbc70a5fdad79e1ec3210385a722db194ffe Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sat, 3 Jan 2015 23:42:19 -0700 Subject: [PATCH 023/142] [visualize/termsAgg] order by either document count or a mertic agg --- .../components/agg_types/_agg_params.js | 2 +- .../components/agg_types/buckets/terms.js | 96 +++++++----- .../agg_types/controls/order_agg.html | 18 +++ src/kibana/components/vis/_agg_config.js | 10 +- src/kibana/components/vis/_agg_configs.js | 2 + src/kibana/plugins/visualize/editor/agg.html | 21 +-- src/kibana/plugins/visualize/editor/agg.js | 120 +-------------- .../plugins/visualize/editor/agg_params.html | 13 ++ .../plugins/visualize/editor/agg_params.js | 144 ++++++++++++++++++ .../visualize/editor/styles/editor.less | 6 + 10 files changed, 257 insertions(+), 175 deletions(-) create mode 100644 src/kibana/components/agg_types/controls/order_agg.html create mode 100644 src/kibana/plugins/visualize/editor/agg_params.html create mode 100644 src/kibana/plugins/visualize/editor/agg_params.js diff --git a/src/kibana/components/agg_types/_agg_params.js b/src/kibana/components/agg_types/_agg_params.js index 79ae567ff5ea9d..2a8c21d1a31098 100644 --- a/src/kibana/components/agg_types/_agg_params.js +++ b/src/kibana/components/agg_types/_agg_params.js @@ -9,7 +9,7 @@ define(function (require) { optioned: Private(require('components/agg_types/param_types/optioned')), regex: Private(require('components/agg_types/param_types/regex')), string: Private(require('components/agg_types/param_types/string')), - raw_json: Private(require('components/agg_types/param_types/raw_json')), + json: Private(require('components/agg_types/param_types/raw_json')), _default: Private(require('components/agg_types/param_types/base')) }; diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index af7d182a04df21..1a0909bba9bff1 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -2,14 +2,14 @@ define(function (require) { return function TermsAggDefinition(Private) { var _ = require('lodash'); var AggType = Private(require('components/agg_types/_agg_type')); - var bucketCountBetween = Private(require('components/agg_types/buckets/_bucket_count_between')); + var AggConfig = Private(require('components/vis/_agg_config')); var createFilter = Private(require('components/agg_types/buckets/create_filter/terms')); return new AggType({ name: 'terms', title: 'Terms', - makeLabel: function (aggConfig) { - var params = aggConfig.params; + makeLabel: function (agg) { + var params = agg.params; return params.order.display + ' ' + params.size + ' ' + params.field.displayName; }, createFilter: createFilter, @@ -19,54 +19,78 @@ define(function (require) { scriptable: true, filterFieldTypes: ['number', 'boolean', 'date', 'ip', 'string'] }, + { + name: 'exclude', + type: 'regex', + advanced: true + }, + { + name: 'include', + type: 'regex', + advanced: true + }, { name: 'size', default: 5 - // editor: batched with order }, { name: 'order', type: 'optioned', + default: 'desc', + editor: require('text!components/agg_types/controls/order_and_size.html'), options: [ { display: 'Top', val: 'desc' }, { display: 'Bottom', val: 'asc' } ], - editor: require('text!components/agg_types/controls/order_and_size.html'), - default: 'desc', - write: function (aggConfig, output) { - var sort = output.params.order = {}; - var order = aggConfig.params.order.val; - - var metricAggConfig = _.first(aggConfig.vis.aggs.bySchemaGroup.metrics); - - if (metricAggConfig.type.name === 'count') { - sort._count = order; - return; - } - - sort[metricAggConfig.id] = order; - - var visNotHierarchical = !aggConfig.vis.isHierarchical(); - - // if the vis is hierarchical, then the metric will always be copied - // if it's not, then we need to make sure the number of buckets is 0, else wise copy it - var metricNotChild = visNotHierarchical && bucketCountBetween(aggConfig, metricAggConfig) !== 0; - - if (metricNotChild) { - output.subAggs = output.subAggs || []; - output.subAggs.push(metricAggConfig); - } - } + write: _.noop // prevent default write, it's handled by orderAgg }, { - name: 'exclude', - type: 'regex', - advanced: true + name: 'orderBy', + type: 'optioned', + default: 'count', + options: [ + { display: 'Document Count', val: 'count' }, + { display: 'Custom Metric', val: 'agg' } + ], + write: _.noop // prevent default write, it's handled by orderAgg }, { - name: 'include', - type: 'regex', - advanced: true + name: 'orderAgg', + type: AggConfig, + default: null, + editor: require('text!components/agg_types/controls/order_agg.html'), + serialize: function (orderAgg) { + return orderAgg.toJSON(); + }, + deserialize: function (stateJSON, aggConfig) { + return new AggConfig(aggConfig.vis, stateJSON); + }, + controller: function ($scope) { + $scope.$watch('params.orderBy', function (orderBy) { + if (!orderBy) return; + if (orderBy.val !== 'agg') { + $scope.params.orderAgg = null; + return; + } + if ($scope.params.orderAgg) return; + + var agg = $scope.aggConfig; + $scope.params.orderAgg = new AggConfig(agg.vis, { + schema: _.first(agg.vis.type.schemas.metrics) + }); + }); + }, + write: function (agg, output) { + var dir = agg.params.order.val; + var order = output.params.order = {}; + + if (agg.params.orderAgg) { + output.subAggs = (output.subAggs || []).concat(agg.params.orderAgg); + order[agg.params.orderAgg.id] = dir; + } else { + order._count = dir; + } + } } ] }); diff --git a/src/kibana/components/agg_types/controls/order_agg.html b/src/kibana/components/agg_types/controls/order_agg.html new file mode 100644 index 00000000000000..e78934bade3755 --- /dev/null +++ b/src/kibana/components/agg_types/controls/order_agg.html @@ -0,0 +1,18 @@ +
+ + +
+
+ + + +
\ No newline at end of file diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index c090014d5ff881..410e3f0c6f8472 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -1,7 +1,6 @@ define(function (require) { return function AggConfigFactory(Private) { var _ = require('lodash'); - var aggTypes = Private(require('components/agg_types/index')); var fieldFormats = Private(require('components/index_patterns/_field_formats')); function AggConfig(vis, opts) { @@ -14,7 +13,7 @@ define(function (require) { // get the config type self.type = opts.type; if (_.isString(self.type)) { - self.type = aggTypes.byName[self.type]; + self.type = AggConfig.aggTypes.byName[self.type]; } // get the config schema @@ -81,8 +80,11 @@ define(function (require) { } if (aggParam.deserialize) { - if (!_.isObject(val)) { - // only deserialize if we have a scalar value + var isType = _.isFunction(aggParam.type) && (val instanceof aggParam.type); + var isObject = !isType && _.isObject(val); + var isDeserialized = (isType || isObject); + + if (!isDeserialized) { val = aggParam.deserialize(val, self); } diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index 24a244e533ae23..54fa834c69ee59 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -4,6 +4,8 @@ define(function (require) { var AggConfig = Private(require('components/vis/_agg_config')); var IndexedArray = require('utils/indexed_array/index'); + AggConfig.aggTypes = Private(require('components/agg_types/index')); + _(AggConfigs).inherits(IndexedArray); function AggConfigs(vis, configStates) { var self = this; diff --git a/src/kibana/plugins/visualize/editor/agg.html b/src/kibana/plugins/visualize/editor/agg.html index 80d0da93534cc9..1fea05ee55f63d 100644 --- a/src/kibana/plugins/visualize/editor/agg.html +++ b/src/kibana/plugins/visualize/editor/agg.html @@ -65,19 +65,10 @@
-
-
-

- "{{ agg.schema.title }}" aggs must run before all other buckets! -

- -
- - -
+ + \ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg.js b/src/kibana/plugins/visualize/editor/agg.js index 62cf305b74643c..beac1560cfd052 100644 --- a/src/kibana/plugins/visualize/editor/agg.js +++ b/src/kibana/plugins/visualize/editor/agg.js @@ -9,7 +9,7 @@ define(function (require) { var advancedToggleHtml = require('text!plugins/visualize/editor/advanced_toggle.html'); require('angular-ui-select'); - require('plugins/visualize/editor/agg_param'); + require('plugins/visualize/editor/agg_params'); require('filters/match_any'); var notify = new Notifier({ @@ -29,9 +29,7 @@ define(function (require) { groupMin: '=' }, link: function ($scope, $el) { - $scope.aggTypeOptions = aggTypes.byType[$scope.groupName]; $scope.editorOpen = $scope.agg.brandNew; - $scope.advancedToggled = false; $scope.$watchMulti([ '$index', @@ -43,122 +41,6 @@ define(function (require) { $scope.aggIsTooLow = calcAggIsTooLow(); }); - (function setupControlManagement() { - var $editorContainer = $el.find('.vis-editor-agg-editor'); - - // this will contain the controls for the schema (rows or columns?), which are unrelated to - // controls for the agg, which is why they are first - var $schemaEditor = $('
').addClass('schemaEditors').appendTo($editorContainer); - - if ($scope.agg.schema.editor) { - $schemaEditor.append($scope.agg.schema.editor); - $compile($schemaEditor)(editorScope()); - } - - // allow selection of an aggregation - var $aggSelect = $(aggSelectHtml).appendTo($editorContainer); - $compile($aggSelect)($scope); - - // params for the selected agg, these are rebuilt every time the agg in $aggSelect changes - var $aggParamEditors; // container for agg type param editors - var $aggParamEditorsScope; - $scope.$watch('agg.type', function updateAggParamEditor(newType, oldType) { - if ($aggParamEditors) { - $aggParamEditors.remove(); - $aggParamEditors = null; - } - - // if there's an old scope, destroy it - if ($aggParamEditorsScope) { - $aggParamEditorsScope.$destroy(); - $aggParamEditorsScope = null; - } - - var agg = $scope.agg; - var type = $scope.agg.type; - - if (!agg) return; - - if (newType !== oldType) { - // don't reset on initial load, the - // saved params should persist - agg.resetParams(); - } - - if (!type) return; - - var aggParamHTML = { - basic: [], - advanced: [] - }; - - // build collection of agg params html - type.params.forEach(function (param, i) { - var aggParam; - var type = 'basic'; - if (param.advanced) type = 'advanced'; - - if (aggParam = getAggParamHTML(param, i)) { - aggParamHTML[type].push(aggParam); - } - }); - - // compile the paramEditors html elements - var paramEditors = aggParamHTML.basic; - - if (aggParamHTML.advanced.length) { - paramEditors.push($(advancedToggleHtml).get(0)); - paramEditors = paramEditors.concat(aggParamHTML.advanced); - } - - $aggParamEditorsScope = $scope.$new(); - $aggParamEditors = $(paramEditors).appendTo($editorContainer); - $compile($aggParamEditors)($aggParamEditorsScope); - }); - - // build HTML editor given an aggParam and index - function getAggParamHTML(param, idx) { - // don't show params without an editor - if (!param.editor) { - return; - } - - var attrs = { - 'agg-type': 'agg.type', - 'agg-config': 'agg', - 'params': 'agg.params' - }; - - attrs['agg-param'] = 'agg.type.params[' + idx + ']'; - if (param.advanced) { - attrs['ng-show'] = 'advancedToggled'; - } - - return $('') - .attr(attrs) - .append(param.editor) - .get(0); - } - - // generic child scope creation, for both schema and agg - function editorScope() { - var $editorScope = $scope.$new(); - - setupBoundProp($editorScope, 'agg.type', 'aggType'); - setupBoundProp($editorScope, 'agg', 'aggConfig'); - setupBoundProp($editorScope, 'agg.params', 'params'); - - return $editorScope; - } - - // bind a property from our scope a child scope, with one-way binding - function setupBoundProp($child, get, set) { - var getter = _.partial($parse(get), $scope); - var setter = _.partial($parse(set).assign, $child); - $scope.$watch(getter, setter); - } - }()); - /** * Describe the aggregation, for display in the collapsed agg header * @return {[type]} [description] diff --git a/src/kibana/plugins/visualize/editor/agg_params.html b/src/kibana/plugins/visualize/editor/agg_params.html new file mode 100644 index 00000000000000..e4473e73a8b2ed --- /dev/null +++ b/src/kibana/plugins/visualize/editor/agg_params.html @@ -0,0 +1,13 @@ +
+

+ "{{ agg.schema.title }}" aggs must run before all other buckets! +

+ +
+ + \ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg_params.js b/src/kibana/plugins/visualize/editor/agg_params.js new file mode 100644 index 00000000000000..4f9a613e322c47 --- /dev/null +++ b/src/kibana/plugins/visualize/editor/agg_params.js @@ -0,0 +1,144 @@ +define(function (require) { + require('modules') + .get('app/visualize', ['ui.select']) + .directive('visEditorAggParams', function ($compile, $parse, Private, Notifier) { + var _ = require('lodash'); + var $ = require('jquery'); + var aggTypes = Private(require('components/agg_types/index')); + var aggSelectHtml = require('text!plugins/visualize/editor/agg_select.html'); + var advancedToggleHtml = require('text!plugins/visualize/editor/advanced_toggle.html'); + require('angular-ui-select'); + + require('plugins/visualize/editor/agg_param'); + require('filters/match_any'); + + var notify = new Notifier({ + location: 'visAggGroup' + }); + + return { + restrict: 'E', + template: require('text!plugins/visualize/editor/agg_params.html'), + scope: { + agg: '=', + groupName: '=' + }, + link: function ($scope, $el) { + $scope.aggTypeOptions = aggTypes.byType[$scope.groupName]; + $scope.advancedToggled = false; + + // this will contain the controls for the schema (rows or columns?), which are unrelated to + // controls for the agg, which is why they are first + var $schemaEditor = $('
').addClass('schemaEditors').appendTo($el); + + if ($scope.agg.schema.editor) { + $schemaEditor.append($scope.agg.schema.editor); + $compile($schemaEditor)(editorScope()); + } + + // allow selection of an aggregation + var $aggSelect = $(aggSelectHtml).appendTo($el); + $compile($aggSelect)($scope); + + // params for the selected agg, these are rebuilt every time the agg in $aggSelect changes + var $aggParamEditors; // container for agg type param editors + var $aggParamEditorsScope; + $scope.$watch('agg.type', function updateAggParamEditor(newType, oldType) { + if ($aggParamEditors) { + $aggParamEditors.remove(); + $aggParamEditors = null; + } + + // if there's an old scope, destroy it + if ($aggParamEditorsScope) { + $aggParamEditorsScope.$destroy(); + $aggParamEditorsScope = null; + } + + var agg = $scope.agg; + if (!agg) return; + + var type = $scope.agg.type; + + if (newType !== oldType) { + // don't reset on initial load, the + // saved params should persist + agg.resetParams(); + } + + if (!type) return; + + var aggParamHTML = { + basic: [], + advanced: [] + }; + + // build collection of agg params html + type.params.forEach(function (param, i) { + var aggParam; + var type = 'basic'; + if (param.advanced) type = 'advanced'; + + if (aggParam = getAggParamHTML(param, i)) { + aggParamHTML[type].push(aggParam); + } + }); + + // compile the paramEditors html elements + var paramEditors = aggParamHTML.basic; + + if (aggParamHTML.advanced.length) { + paramEditors.push($(advancedToggleHtml).get(0)); + paramEditors = paramEditors.concat(aggParamHTML.advanced); + } + + $aggParamEditorsScope = $scope.$new(); + $aggParamEditors = $(paramEditors).appendTo($el); + $compile($aggParamEditors)($aggParamEditorsScope); + }); + + // build HTML editor given an aggParam and index + function getAggParamHTML(param, idx) { + // don't show params without an editor + if (!param.editor) { + return; + } + + var attrs = { + 'agg-type': 'agg.type', + 'agg-config': 'agg', + 'params': 'agg.params' + }; + + attrs['agg-param'] = 'agg.type.params[' + idx + ']'; + if (param.advanced) { + attrs['ng-show'] = 'advancedToggled'; + } + + return $('') + .attr(attrs) + .append(param.editor) + .get(0); + } + + // generic child scope creation, for both schema and agg + function editorScope() { + var $editorScope = $scope.$new(); + + setupBoundProp($editorScope, 'agg.type', 'aggType'); + setupBoundProp($editorScope, 'agg', 'aggConfig'); + setupBoundProp($editorScope, 'agg.params', 'params'); + + return $editorScope; + } + + // bind a property from our scope a child scope, with one-way binding + function setupBoundProp($child, get, set) { + var getter = _.partial($parse(get), $scope); + var setter = _.partial($parse(set).assign, $child); + $scope.$watch(getter, setter); + } + } + }; + }); +}); \ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index 500881273c9f4e..f9ff1bb98fb482 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -227,6 +227,12 @@ margin: 0 0 5px 0; } } + + &-order-agg { + border-left: 2px solid @gray-lighter; + margin-left: @vis-editor-agg-editor-spacing; + padding-left: @vis-editor-agg-editor-spacing; + } } &-canvas { From 2765863a4fd3074e6e090a05a643aaf35322ae11 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 12:57:54 -0700 Subject: [PATCH 024/142] [visualize/editor] allow ordering by existing metric aggs --- .../components/agg_types/buckets/terms.js | 45 ++++++++++++------- .../agg_types/controls/order_agg.html | 44 +++++++++++------- src/kibana/components/vis/_agg_config.js | 6 ++- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index 1a0909bba9bff1..e639059e1c4fc6 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -46,12 +46,6 @@ define(function (require) { }, { name: 'orderBy', - type: 'optioned', - default: 'count', - options: [ - { display: 'Document Count', val: 'count' }, - { display: 'Custom Metric', val: 'agg' } - ], write: _.noop // prevent default write, it's handled by orderAgg }, { @@ -66,16 +60,32 @@ define(function (require) { return new AggConfig(aggConfig.vis, stateJSON); }, controller: function ($scope) { - $scope.$watch('params.orderBy', function (orderBy) { + $scope.safeMakeLabel = function (agg) { + try { + return agg.makeLabel(); + } catch (e) { + return '- agg not valid -'; + } + }; + + $scope.$watch('params.orderBy', function (orderBy, prevOrderBy) { + var agg = $scope.aggConfig; + var aggs = agg.vis.aggs; + var params = $scope.params; + + if (orderBy === prevOrderBy && !orderBy) { + params.orderBy = (_.first(aggs.bySchemaGroup.metrics) || { id: 'custom' }).id; + return; + } + if (!orderBy) return; - if (orderBy.val !== 'agg') { - $scope.params.orderAgg = null; + if (orderBy !== 'custom') { + params.orderAgg = null; return; } - if ($scope.params.orderAgg) return; + if (params.orderAgg) return; - var agg = $scope.aggConfig; - $scope.params.orderAgg = new AggConfig(agg.vis, { + params.orderAgg = new AggConfig(agg.vis, { schema: _.first(agg.vis.type.schemas.metrics) }); }); @@ -84,12 +94,13 @@ define(function (require) { var dir = agg.params.order.val; var order = output.params.order = {}; - if (agg.params.orderAgg) { - output.subAggs = (output.subAggs || []).concat(agg.params.orderAgg); - order[agg.params.orderAgg.id] = dir; - } else { - order._count = dir; + var orderAgg = agg.params.orderAgg; + if (!orderAgg) { + orderAgg = agg.vis.aggs.byId[agg.params.orderBy]; } + + output.subAggs = (output.subAggs || []).concat(orderAgg); + order[orderAgg.id] = dir; } } ] diff --git a/src/kibana/components/agg_types/controls/order_agg.html b/src/kibana/components/agg_types/controls/order_agg.html index e78934bade3755..095031349755c9 100644 --- a/src/kibana/components/agg_types/controls/order_agg.html +++ b/src/kibana/components/agg_types/controls/order_agg.html @@ -1,18 +1,28 @@ -
- - -
-
- - - +
+
+ + +
+
+ + + +
\ No newline at end of file diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index 410e3f0c6f8472..386f5c45aa73af 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -80,8 +80,10 @@ define(function (require) { } if (aggParam.deserialize) { - var isType = _.isFunction(aggParam.type) && (val instanceof aggParam.type); - var isObject = !isType && _.isObject(val); + var isTyped = _.isFunction(aggParam.type); + + var isType = isTyped && (val instanceof aggParam.type); + var isObject = !isTyped && _.isObject(val); var isDeserialized = (isType || isObject); if (!isDeserialized) { From 0111a0d0ab44fbf3c300db6b8adf45ff5615a2c6 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 13:08:21 -0700 Subject: [PATCH 025/142] [visualize/editor] prevent stacking advanced toggles --- src/kibana/plugins/visualize/editor/advanced_toggle.html | 2 +- src/kibana/plugins/visualize/editor/styles/editor.less | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/advanced_toggle.html b/src/kibana/plugins/visualize/editor/advanced_toggle.html index 321d5ef7d78856..040a155cd45912 100644 --- a/src/kibana/plugins/visualize/editor/advanced_toggle.html +++ b/src/kibana/plugins/visualize/editor/advanced_toggle.html @@ -1,4 +1,4 @@ -
+
Advanced diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index f9ff1bb98fb482..fa17829122b252 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -188,6 +188,10 @@ color: @link-color; } } + + &-advanced-toggle { + text-align: right; + } } &-form-row { @@ -230,8 +234,9 @@ &-order-agg { border-left: 2px solid @gray-lighter; - margin-left: @vis-editor-agg-editor-spacing; - padding-left: @vis-editor-agg-editor-spacing; + border-bottom: 2px solid @gray-lighter; + margin: 0 0 @vis-editor-agg-editor-spacing @vis-editor-agg-editor-spacing; + padding: 0 0 @vis-editor-agg-editor-spacing @vis-editor-agg-editor-spacing; } } From 7d661fb12f7fa4e03cd2355e1cad55548a7853be Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 13:18:11 -0700 Subject: [PATCH 026/142] [vis/aggConfigs/tests] proxy the aggTypes to AggConfig spy --- test/unit/specs/components/vis/_agg_configs.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unit/specs/components/vis/_agg_configs.js b/test/unit/specs/components/vis/_agg_configs.js index 5e984098bd73c5..04503641e9dc75 100644 --- a/test/unit/specs/components/vis/_agg_configs.js +++ b/test/unit/specs/components/vis/_agg_configs.js @@ -16,7 +16,13 @@ define(function (require) { // replace the AggConfig module with a spy var RealAggConfigPM = require('components/vis/_agg_config'); AggConfig = Private(RealAggConfigPM); - Private.stub(RealAggConfigPM, sinon.spy(AggConfig)); + var spy = sinon.spy(AggConfig); + Object.defineProperty(spy, 'aggTypes', { + get: function () { return AggConfig.aggTypes; }, + set: function (val) { AggConfig.aggTypes = val; } + }); + + Private.stub(RealAggConfigPM, spy); // load main deps Vis = Private(require('components/vis/vis')); From 80a807137c2173aeb589a25f01a4b7b248be44da Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 13:18:38 -0700 Subject: [PATCH 027/142] [vis/aggConfigs/tests] specify the required orderBy param --- test/unit/specs/components/vis/_agg_configs.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/specs/components/vis/_agg_configs.js b/test/unit/specs/components/vis/_agg_configs.js index 04503641e9dc75..f99d9ab410dc45 100644 --- a/test/unit/specs/components/vis/_agg_configs.js +++ b/test/unit/specs/components/vis/_agg_configs.js @@ -276,9 +276,9 @@ define(function (require) { var vis = new Vis(indexPattern, { type: 'histogram', aggs: [ - { type: 'terms', schema: 'segment', params: { field: 'ip' } }, - { type: 'terms', schema: 'segment', params: { field: 'extension' } }, - { type: 'avg', schema: 'metric', params: { field: 'bytes' } }, + { type: 'terms', schema: 'segment', params: { field: 'ip', orderBy: 1 } }, + { type: 'terms', schema: 'segment', params: { field: 'extension', orderBy: 1 } }, + { id: 1, type: 'avg', schema: 'metric', params: { field: 'bytes' } }, { type: 'sum', schema: 'metric', params: { field: 'bytes' } }, { type: 'min', schema: 'metric', params: { field: 'bytes' } }, { type: 'max', schema: 'metric', params: { field: 'bytes' } } From 904968c7730d0c6418585c082da5ea64f255c5ab Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 13:20:22 -0700 Subject: [PATCH 028/142] [aggTypes/aggParams/test] removed this unused behavior --- test/unit/specs/components/agg_types/_agg_params.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/test/unit/specs/components/agg_types/_agg_params.js b/test/unit/specs/components/agg_types/_agg_params.js index a0ddc271198794..ecf7f86f59d34e 100644 --- a/test/unit/specs/components/agg_types/_agg_params.js +++ b/test/unit/specs/components/agg_types/_agg_params.js @@ -21,19 +21,6 @@ define(function (require) { })); describe('constructor args', function () { - it('accepts an object of params defs', function () { - var params = { - one: {}, - two: {} - }; - var paramLength = Object.keys(params).length + 1; // json is appended - var aggParams = new AggParams(params); - - expect(aggParams).to.have.length(paramLength); - expect(aggParams).to.be.an(Array); - expect(aggParams.byName).to.have.keys(['one', 'two']); - }); - it('accepts an array of param defs', function () { var params = [ { name: 'one' }, From 9255c3d3d50b0a718b867da596f610f4a898ba79 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 13:22:56 -0700 Subject: [PATCH 029/142] [aggTypes/aggParams/tests] json agg param is now appended by AggType so that AggParams is more reusable --- .../specs/components/agg_types/_agg_params.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/test/unit/specs/components/agg_types/_agg_params.js b/test/unit/specs/components/agg_types/_agg_params.js index ecf7f86f59d34e..d95af688668554 100644 --- a/test/unit/specs/components/agg_types/_agg_params.js +++ b/test/unit/specs/components/agg_types/_agg_params.js @@ -26,10 +26,9 @@ define(function (require) { { name: 'one' }, { name: 'two' } ]; - var paramLength = params.length + 1; // json is appended var aggParams = new AggParams(params); - expect(aggParams).to.have.length(paramLength); + expect(aggParams).to.have.length(params.length); expect(aggParams).to.be.an(Array); expect(aggParams.byName).to.have.keys(['one', 'two']); }); @@ -40,10 +39,9 @@ define(function (require) { var params = [ { name: 'field' } ]; - var paramLength = params.length + 1; // json is appended var aggParams = new AggParams(params); - expect(aggParams).to.have.length(paramLength); + expect(aggParams).to.have.length(params.length); expect(aggParams[0]).to.be.a(FieldAggParam); }); @@ -54,10 +52,9 @@ define(function (require) { type: 'optioned' } ]; - var paramLength = params.length + 1; // json is appended var aggParams = new AggParams(params); - expect(aggParams).to.have.length(paramLength); + expect(aggParams).to.have.length(params.length); expect(aggParams[0]).to.be.a(OptionedAggParam); }); @@ -68,10 +65,9 @@ define(function (require) { type: 'regex' } ]; - var paramLength = params.length + 1; // json is appended var aggParams = new AggParams(params); - expect(aggParams).to.have.length(paramLength); + expect(aggParams).to.have.length(params.length); expect(aggParams[0]).to.be.a(RegexAggParam); }); @@ -90,14 +86,13 @@ define(function (require) { editor: 'small' } ]; - var paramLength = params.length + 1; // json is appended var aggParams = new AggParams(params); - expect(BaseAggParam).to.have.property('callCount', paramLength); + expect(BaseAggParam).to.have.property('callCount', params.length); expect(FieldAggParam).to.have.property('callCount', 0); expect(OptionedAggParam).to.have.property('callCount', 0); - expect(aggParams).to.have.length(paramLength); + expect(aggParams).to.have.length(params.length); aggParams.forEach(function (aggParam) { expect(aggParam).to.be.a(BaseAggParam); }); From e8e70a4340696d064d39ecd25c2435e251c9a608 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 15:42:59 -0700 Subject: [PATCH 030/142] [aggConfigs/responseValueAggs] standardize naming --- src/kibana/components/agg_types/_agg_type.js | 4 ++-- src/kibana/components/agg_types/metrics/percentiles.js | 2 +- src/kibana/components/vis/_agg_config.js | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/kibana/components/agg_types/_agg_type.js b/src/kibana/components/agg_types/_agg_type.js index 79d03af11c05a8..fe822c064b05ba 100644 --- a/src/kibana/components/agg_types/_agg_type.js +++ b/src/kibana/components/agg_types/_agg_type.js @@ -96,12 +96,12 @@ define(function (require) { * set of AggConfigs that should replace this aggConfig in result sets * that walk the AggConfig set. * - * @method getReplacementAggs + * @method getResponseValueAggs * @returns {array[AggConfig]|undefined} - an array of aggConfig objects * that should replace this one, * or undefined */ - this.getReplacementAggs = config.getReplacementAggs || _.noop; + this.getResponseValueAggs = config.getResponseValueAggs || _.noop; } return AggType; diff --git a/src/kibana/components/agg_types/metrics/percentiles.js b/src/kibana/components/agg_types/metrics/percentiles.js index e6c101a9a2157b..264aa152022989 100644 --- a/src/kibana/components/agg_types/metrics/percentiles.js +++ b/src/kibana/components/agg_types/metrics/percentiles.js @@ -32,7 +32,7 @@ define(function (require) { default: [1, 5, 25, 50, 75, 95, 99] } ], - getReplacementAggs: function (agg) { + getResponseValueAggs: function (agg) { var ValueAggConfig = getValueAggConfig(agg, valueProps); return agg.params.percents.map(function (percent) { diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index 9819d8cc2e4366..fb12306600fbfa 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -189,8 +189,10 @@ define(function (require) { ); }; - AggConfig.prototype.getReplacements = function () { - return this.type.getReplacementAggs && this.type.getReplacementAggs(this); + AggConfig.prototype.getResponseValueAggs = function () { + if (_.isFunction(this.type.getResponseValueAggs)) { + return this.type.getResponseValueAggs(this); + } }; AggConfig.prototype.getValue = function (bucket) { From eb5256a42253b42b80626f4e993949b34a59e914 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 15:53:59 -0700 Subject: [PATCH 031/142] [aggTypes/terms] special behavior for sorting by count agg --- src/kibana/components/agg_types/buckets/terms.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index e639059e1c4fc6..7ff72816189478 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -99,8 +99,12 @@ define(function (require) { orderAgg = agg.vis.aggs.byId[agg.params.orderBy]; } - output.subAggs = (output.subAggs || []).concat(orderAgg); - order[orderAgg.id] = dir; + if (orderAgg.type.name === 'count') { + order._count = dir; + } else { + output.subAggs = (output.subAggs || []).concat(orderAgg); + order[orderAgg.id] = dir; + } } } ] From 7657b093e4bb363629ab5fce2a641ca5a42b01ca Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 15:43:25 -0700 Subject: [PATCH 032/142] [aggConfigs/responseValueAggs] add getter to AggConfigs --- .../agg_response/tabify/_get_columns.js | 7 +------ src/kibana/components/vis/_agg_configs.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/kibana/components/agg_response/tabify/_get_columns.js b/src/kibana/components/agg_response/tabify/_get_columns.js index 6d731405f5b5b9..4d07200db43f00 100644 --- a/src/kibana/components/agg_response/tabify/_get_columns.js +++ b/src/kibana/components/agg_response/tabify/_get_columns.js @@ -4,12 +4,7 @@ define(function (require) { var AggConfig = Private(require('components/vis/_agg_config')); return function getColumns(vis, minimal) { - var aggs = _(vis.aggs.getSorted()) - .map(function (agg) { - return agg.getReplacements() || agg; - }) - .flatten() - .value(); + var aggs = vis.aggs.getResponseValueAggs(); if (minimal == null) minimal = !vis.isHierarchical(); diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index 54fa834c69ee59..330a01fd698ccc 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -106,6 +106,23 @@ define(function (require) { }); }; + /** + * Gets the AggConfigs (and possibly ValueAggConfigs) that + * represent the values that will be produced when all aggs + * are run. + * + * With multi-value metric aggs it is possible for a single agg + * request to result in multiple agg values, which is why the length + * of a vis' responseValuesAggs may be different than the vis' aggs + * + * @return {array[AggConfig]} + */ + AggConfigs.prototype.getResponseValueAggs = function () { + return this.getSorted().reduce(function (responseValuesAggs, agg) { + return responseValuesAggs.concat(agg.getResponseValueAggs() || agg); + }, []); + }; + return AggConfigs; }; }); From 47d26452d49f0579238855882e73de2cc193e642 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 18:11:04 -0700 Subject: [PATCH 033/142] [aggConfigs/responseValueAggs] standardize naming further --- .../agg_response/tabify/_get_columns.js | 2 +- src/kibana/components/agg_types/_agg_type.js | 4 ++-- .../buckets/_bucket_count_between.js | 2 +- ..._config.js => _get_response_agg_config.js} | 24 +++++++++---------- .../agg_types/metrics/percentiles.js | 6 ++--- src/kibana/components/vis/_agg_config.js | 7 +++--- src/kibana/components/vis/_agg_configs.js | 13 +++++----- .../unit/specs/components/vis/_agg_configs.js | 8 +++---- 8 files changed, 33 insertions(+), 33 deletions(-) rename src/kibana/components/agg_types/metrics/{_get_value_agg_config.js => _get_response_agg_config.js} (58%) diff --git a/src/kibana/components/agg_response/tabify/_get_columns.js b/src/kibana/components/agg_response/tabify/_get_columns.js index 4d07200db43f00..cfa9fdfaeabbb7 100644 --- a/src/kibana/components/agg_response/tabify/_get_columns.js +++ b/src/kibana/components/agg_response/tabify/_get_columns.js @@ -4,7 +4,7 @@ define(function (require) { var AggConfig = Private(require('components/vis/_agg_config')); return function getColumns(vis, minimal) { - var aggs = vis.aggs.getResponseValueAggs(); + var aggs = vis.aggs.getResponseAggs(); if (minimal == null) minimal = !vis.isHierarchical(); diff --git a/src/kibana/components/agg_types/_agg_type.js b/src/kibana/components/agg_types/_agg_type.js index fe822c064b05ba..858f9fa13dc90f 100644 --- a/src/kibana/components/agg_types/_agg_type.js +++ b/src/kibana/components/agg_types/_agg_type.js @@ -96,12 +96,12 @@ define(function (require) { * set of AggConfigs that should replace this aggConfig in result sets * that walk the AggConfig set. * - * @method getResponseValueAggs + * @method getResponseAggs * @returns {array[AggConfig]|undefined} - an array of aggConfig objects * that should replace this one, * or undefined */ - this.getResponseValueAggs = config.getResponseValueAggs || _.noop; + this.getResponseAggs = config.getResponseAggs || _.noop; } return AggType; diff --git a/src/kibana/components/agg_types/buckets/_bucket_count_between.js b/src/kibana/components/agg_types/buckets/_bucket_count_between.js index 379dc09300e276..59b5ebab12585b 100644 --- a/src/kibana/components/agg_types/buckets/_bucket_count_between.js +++ b/src/kibana/components/agg_types/buckets/_bucket_count_between.js @@ -14,7 +14,7 @@ define(function (require) { * @return {null|number} */ function bucketCountBetween(aggConfigA, aggConfigB) { - var aggs = aggConfigA.vis.aggs.getSorted(); + var aggs = aggConfigA.vis.aggs.getRequestAggs(); var aIndex = aggs.indexOf(aggConfigA); var bIndex = aggs.indexOf(aggConfigB); diff --git a/src/kibana/components/agg_types/metrics/_get_value_agg_config.js b/src/kibana/components/agg_types/metrics/_get_response_agg_config.js similarity index 58% rename from src/kibana/components/agg_types/metrics/_get_value_agg_config.js rename to src/kibana/components/agg_types/metrics/_get_response_agg_config.js index da6e591046731b..aca0018d168232 100644 --- a/src/kibana/components/agg_types/metrics/_get_value_agg_config.js +++ b/src/kibana/components/agg_types/metrics/_get_response_agg_config.js @@ -1,20 +1,20 @@ define(function (require) { - return function ValueAggConfigProvider() { + return function ResponseAggConfigProvider() { var _ = require('lodash'); /** - * Get the ValueAggConfig class for an aggConfig, + * Get the ResponseAggConfig class for an aggConfig, * which might be cached on the aggConfig or created. * * @param {AggConfig} agg - the AggConfig the VAC should inherit from * @param {object} props - properties that the VAC should have * @return {Constructor} - a constructor for VAC objects that will inherit the aggConfig */ - return function getValueConfigClass(agg, props) { - if (agg.$$_ValueAggConfigClass) { - return agg.$$_ValueAggConfigClass; + return function getResponseConfigClass(agg, props) { + if (agg.$$_ResponseAggConfigClass) { + return agg.$$_ResponseAggConfigClass; } else { - return (agg.$$_ValueAggConfigClass = create(agg, props)); + return (agg.$$_ResponseAggConfigClass = create(agg, props)); } }; @@ -27,19 +27,19 @@ define(function (require) { * @param {string|number} key - the key or index that identifies * this part of the multi-value */ - function ValueAggConfig(key) { + function ResponseAggConfig(key) { this.key = key; this.parentId = this.id; - this.id = this.parentId + '$$' + key; + this.id = this.parentId + '.' + key; } - ValueAggConfig.prototype = Object.create(parentAgg, { - constructor: ValueAggConfig + ResponseAggConfig.prototype = Object.create(parentAgg, { + constructor: ResponseAggConfig }); - _.assign(ValueAggConfig.prototype, props); + _.assign(ResponseAggConfig.prototype, props); - return ValueAggConfig; + return ResponseAggConfig; } }; }); \ No newline at end of file diff --git a/src/kibana/components/agg_types/metrics/percentiles.js b/src/kibana/components/agg_types/metrics/percentiles.js index 264aa152022989..263823b1cc471a 100644 --- a/src/kibana/components/agg_types/metrics/percentiles.js +++ b/src/kibana/components/agg_types/metrics/percentiles.js @@ -3,7 +3,7 @@ define(function (require) { var _ = require('lodash'); var MetricAggType = Private(require('components/agg_types/metrics/_metric_agg_type')); - var getValueAggConfig = Private(require('components/agg_types/metrics/_get_value_agg_config')); + var getResponseAggConfig = Private(require('components/agg_types/metrics/_get_response_agg_config')); var ordinalSuffix = require('utils/ordinal_suffix'); require('components/agg_types/controls/_percent_list'); @@ -32,8 +32,8 @@ define(function (require) { default: [1, 5, 25, 50, 75, 95, 99] } ], - getResponseValueAggs: function (agg) { - var ValueAggConfig = getValueAggConfig(agg, valueProps); + getResponseAggs: function (agg) { + var ValueAggConfig = getResponseAggConfig(agg, valueProps); return agg.params.percents.map(function (percent) { return new ValueAggConfig(percent); diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index fb12306600fbfa..ef49691be5804b 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -189,10 +189,9 @@ define(function (require) { ); }; - AggConfig.prototype.getResponseValueAggs = function () { - if (_.isFunction(this.type.getResponseValueAggs)) { - return this.type.getResponseValueAggs(this); - } + AggConfig.prototype.getResponseAggs = function () { + if (!this.type) return; + return this.type.getResponseAggs(this) || this; }; AggConfig.prototype.getValue = function (bucket) { diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index 330a01fd698ccc..9258dc3b72b18d 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -64,7 +64,7 @@ define(function (require) { }); } - this.getSorted() + this.getRequestAggs() .filter(function (config) { return !config.type.hasNoDsl; }) @@ -100,14 +100,14 @@ define(function (require) { return dslTopLvl; }; - AggConfigs.prototype.getSorted = function () { + AggConfigs.prototype.getRequestAggs = function () { return _.sortBy(this, function (agg) { return agg.schema.group === 'metrics' ? 1 : 0; }); }; /** - * Gets the AggConfigs (and possibly ValueAggConfigs) that + * Gets the AggConfigs (and possibly ResponseAggConfigs) that * represent the values that will be produced when all aggs * are run. * @@ -117,9 +117,10 @@ define(function (require) { * * @return {array[AggConfig]} */ - AggConfigs.prototype.getResponseValueAggs = function () { - return this.getSorted().reduce(function (responseValuesAggs, agg) { - return responseValuesAggs.concat(agg.getResponseValueAggs() || agg); + AggConfigs.prototype.getResponseAggs = function () { + return this.getRequestAggs().reduce(function (responseValuesAggs, agg) { + var aggs = agg.getResponseAggs(); + return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; }, []); }; diff --git a/test/unit/specs/components/vis/_agg_configs.js b/test/unit/specs/components/vis/_agg_configs.js index f99d9ab410dc45..fc5a5271f32b9f 100644 --- a/test/unit/specs/components/vis/_agg_configs.js +++ b/test/unit/specs/components/vis/_agg_configs.js @@ -146,7 +146,7 @@ define(function (require) { }); }); - describe('#getSorted', function () { + describe('#getRequestAggs', function () { it('performs a stable sort, but moves metrics to the bottom', function () { var vis = new Vis(indexPattern, { type: 'histogram', @@ -169,7 +169,7 @@ define(function (require) { var dateHisto = vis.aggs.byTypeName.date_histogram[0]; var filters = vis.aggs.byTypeName.filters[0]; - var sorted = vis.aggs.getSorted(); + var sorted = vis.aggs.getRequestAggs(); expect(sorted.shift()).to.be(terms); expect(sorted.shift()).to.be(histo); @@ -185,9 +185,9 @@ define(function (require) { describe('#toDsl', function () { it('uses the sorted aggs', function () { var vis = new Vis(indexPattern, { type: 'histogram' }); - sinon.spy(vis.aggs, 'getSorted'); + sinon.spy(vis.aggs, 'getRequestAggs'); vis.aggs.toDsl(); - expect(vis.aggs.getSorted).to.have.property('callCount', 1); + expect(vis.aggs.getRequestAggs).to.have.property('callCount', 1); }); it('calls aggConfig#toDsl() on each aggConfig and compiles the nested output', function () { From 79a714927bf037ff723331b0e33829d6dca7ad50 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Sun, 4 Jan 2015 18:15:37 -0700 Subject: [PATCH 034/142] [visualize/editor] propogate move to child scopes in editor --- .../agg_types/controls/order_agg.html | 1 - src/kibana/components/bind.js | 34 +++++++++++++++++++ src/kibana/plugins/kibana/index.js | 1 + src/kibana/plugins/visualize/editor/agg.html | 2 +- src/kibana/plugins/visualize/editor/agg.js | 11 ------ .../plugins/visualize/editor/agg_group.html | 9 +---- .../plugins/visualize/editor/agg_group.js | 12 +++---- .../plugins/visualize/editor/agg_params.js | 10 +++--- .../plugins/visualize/editor/editor.html | 7 +--- .../plugins/visualize/editor/sidebar.html | 24 +++---------- .../plugins/visualize/editor/sidebar.js | 9 ++--- 11 files changed, 55 insertions(+), 65 deletions(-) create mode 100644 src/kibana/components/bind.js diff --git a/src/kibana/components/agg_types/controls/order_agg.html b/src/kibana/components/agg_types/controls/order_agg.html index d9a13b84eabcac..c6b8eaf550cee2 100644 --- a/src/kibana/components/agg_types/controls/order_agg.html +++ b/src/kibana/components/agg_types/controls/order_agg.html @@ -18,7 +18,6 @@
-
diff --git a/src/kibana/plugins/visualize/editor/agg_group.js b/src/kibana/plugins/visualize/editor/agg_group.js index c970dc4a49d614..0e491e9100ad52 100644 --- a/src/kibana/plugins/visualize/editor/agg_group.js +++ b/src/kibana/plugins/visualize/editor/agg_group.js @@ -12,13 +12,11 @@ define(function (require) { restrict: 'E', template: require('text!plugins/visualize/editor/agg_group.html'), replace: true, - scope: { - vis: '=', - schemas: '=', - group: '=', - groupName: '=' - }, - link: function ($scope) { + scope: true, + link: function ($scope, $el, attr) { + $scope.groupName = attr.groupName; + $scope.$bind('group', 'vis.aggs.bySchemaGroup["' + $scope.groupName + '"]'); + $scope.$bind('schemas', 'vis.type.schemas["' + $scope.groupName + '"]'); // "sub-scope" for the add form to use $scope.addForm = {}; diff --git a/src/kibana/plugins/visualize/editor/agg_params.js b/src/kibana/plugins/visualize/editor/agg_params.js index 177e2a915e0d33..bd967e491693fd 100644 --- a/src/kibana/plugins/visualize/editor/agg_params.js +++ b/src/kibana/plugins/visualize/editor/agg_params.js @@ -18,11 +18,11 @@ define(function (require) { return { restrict: 'E', template: require('text!plugins/visualize/editor/agg_params.html'), - scope: { - agg: '=', - groupName: '=' - }, - link: function ($scope, $el) { + scope: true, + link: function ($scope, $el, attr) { + $scope.$bind('agg', attr.agg); + $scope.$bind('groupName', attr.groupName); + $scope.aggTypeOptions = aggTypes.byType[$scope.groupName]; $scope.advancedToggled = false; diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html index 4d933ed742185c..3a4e60b1b22b8b 100644 --- a/src/kibana/plugins/visualize/editor/editor.html +++ b/src/kibana/plugins/visualize/editor/editor.html @@ -97,12 +97,7 @@
- - +
diff --git a/src/kibana/plugins/visualize/editor/sidebar.html b/src/kibana/plugins/visualize/editor/sidebar.html index f30f85bf0a663f..3ed3d9278d0908 100644 --- a/src/kibana/plugins/visualize/editor/sidebar.html +++ b/src/kibana/plugins/visualize/editor/sidebar.html @@ -2,30 +2,14 @@ \ No newline at end of file diff --git a/src/kibana/plugins/discover/controllers/discover.js b/src/kibana/plugins/discover/controllers/discover.js index 54d7d6a3eaca5f..b05ca1cee5b712 100644 --- a/src/kibana/plugins/discover/controllers/discover.js +++ b/src/kibana/plugins/discover/controllers/discover.js @@ -73,25 +73,24 @@ define(function (require) { // the actual courier.SearchSource $scope.searchSource = savedSearch.searchSource; - // Manage state & url state - var initialQuery = $scope.searchSource.get('query'); - if (savedSearch.id) { docTitle.change(savedSearch.title); } - var stateDefaults = { - query: initialQuery || '', - sort: savedSearch.sort || [], - columns: savedSearch.columns || ['_source'], - index: $scope.searchSource.get('index').id || config.get('defaultIndex'), - interval: 'auto', - filters: _.cloneDeep($scope.searchSource.get('filter')) - }; + var $state = $scope.state = new AppState(getStateDefaults()); - var metaFields = config.get('metaFields'); + function getStateDefaults() { + return { + query: $scope.searchSource.get('query') || '', + sort: savedSearch.sort || [], + columns: savedSearch.columns || ['_source'], + index: $scope.searchSource.get('index').id || config.get('defaultIndex'), + interval: 'auto', + filters: _.cloneDeep($scope.searchSource.get('filter')) + }; + } - var $state = $scope.state = new AppState(stateDefaults); + var metaFields = config.get('metaFields'); if (!_.contains(indexPatternList, $state.index)) { var reason = 'The index specified in the URL is not a configured pattern. '; @@ -252,6 +251,9 @@ define(function (require) { notify.info('Saved Data Source "' + savedSearch.title + '"'); if (savedSearch.id !== $route.current.params.id) { kbnUrl.change('/discover/{{id}}', { id: savedSearch.id }); + } else { + // Update defaults so that "reload saved query" functions correctly + $state.setDefaults(getStateDefaults()); } } }); From 52a0f328aea7bfbd34404865292ecdb7a533a6fd Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Tue, 6 Jan 2015 11:19:42 -0700 Subject: [PATCH 065/142] Remove references to discover table directive --- .../plugins/discover/directives/table.js | 43 ------------------- .../plugins/discover/partials/table.html | 18 -------- .../doc_table/lib/rows_headers.js} | 3 +- 3 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 src/kibana/plugins/discover/directives/table.js delete mode 100644 src/kibana/plugins/discover/partials/table.html rename test/unit/specs/{apps/discover/directives/table.js => components/doc_table/lib/rows_headers.js} (99%) diff --git a/src/kibana/plugins/discover/directives/table.js b/src/kibana/plugins/discover/directives/table.js deleted file mode 100644 index 9b9cda7be72b38..00000000000000 --- a/src/kibana/plugins/discover/directives/table.js +++ /dev/null @@ -1,43 +0,0 @@ -define(function (require) { - var html = require('text!plugins/discover/partials/table.html'); - - require('directives/truncated'); - require('directives/infinite_scroll'); - require('components/doc_table/components/table_header'); - require('components/doc_table/components/table_row'); - - var module = require('modules').get('app/discover'); - - /** - * kbnTable directive - * - * displays results in a simple table view. Pass the result object - * via the results attribute on the kbnTable element: - * ``` - * - * ``` - */ - module.directive('kbnTable', function (config) { - return { - restrict: 'E', - template: html, - scope: { - columns: '=', - rows: '=', - sorting: '=', - filtering: '=', - refresh: '=', - indexPattern: '=', - }, - link: function ($scope, $el) { - $scope.limit = 50; - $scope.addRows = function () { - if ($scope.limit < config.get('discover:sampleSize')) { - $scope.limit = $scope.limit + 50; - } - }; - } - }; - }); - -}); diff --git a/src/kibana/plugins/discover/partials/table.html b/src/kibana/plugins/discover/partials/table.html deleted file mode 100644 index 3f98d17c8669fc..00000000000000 --- a/src/kibana/plugins/discover/partials/table.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -
- \ No newline at end of file diff --git a/test/unit/specs/apps/discover/directives/table.js b/test/unit/specs/components/doc_table/lib/rows_headers.js similarity index 99% rename from test/unit/specs/apps/discover/directives/table.js rename to test/unit/specs/components/doc_table/lib/rows_headers.js index 271920149a9775..10ada1d42186fd 100644 --- a/test/unit/specs/apps/discover/directives/table.js +++ b/test/unit/specs/components/doc_table/lib/rows_headers.js @@ -82,8 +82,7 @@ define(function (require) { }; - - describe('discover table directives', function () { + describe('Doc Table', function () { describe('kbnTableHeader', function () { From 49b7f461325c6742a63b9e4bda00dbfffe57dc68 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Tue, 6 Jan 2015 11:20:05 -0700 Subject: [PATCH 066/142] Replace discover table with reusable doc-table directive --- .../doc_table/components/table_header.js | 14 +++++++++++--- src/kibana/components/doc_table/doc_table.html | 3 ++- .../plugins/discover/controllers/discover.js | 2 -- src/kibana/plugins/discover/index.html | 14 ++------------ src/kibana/plugins/discover/index.js | 1 - 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/kibana/components/doc_table/components/table_header.js b/src/kibana/components/doc_table/components/table_header.js index f739b0273fbfe3..f23b43701532f3 100644 --- a/src/kibana/components/doc_table/components/table_header.js +++ b/src/kibana/components/doc_table/components/table_header.js @@ -46,11 +46,19 @@ define(function (require) { }; $scope.sort = function (column) { - if (!sortableField(column)) return; + if (!column || !sortableField(column)) return; + + var sorting = $scope.sorting = $scope.sorting || []; + + var direction = sorting[1] || 'asc'; + if (sorting[0] !== column) { + direction = 'asc'; + } else { + direction = sorting[1] === 'asc' ? 'desc' : 'asc'; + } - var sorting = $scope.sorting || []; $scope.sorting[0] = column; - $scope.sorting[1] = (sorting[0] === column && sorting[1] === 'asc') ? 'desc' : 'asc'; + $scope.sorting[1] = direction; }; } }; diff --git a/src/kibana/components/doc_table/doc_table.html b/src/kibana/components/doc_table/doc_table.html index 3c5ee491218768..a56dd5e31966c7 100644 --- a/src/kibana/components/doc_table/doc_table.html +++ b/src/kibana/components/doc_table/doc_table.html @@ -1,4 +1,3 @@ -{{hits.length}}
@@ -31,6 +31,7 @@ columns="columns" sorting="sorting" index-pattern="indexPattern" + filter="filter" class="discover-table-row"> diff --git a/src/kibana/plugins/discover/controllers/discover.js b/src/kibana/plugins/discover/controllers/discover.js index 956c1c61673c79..80577ff64a3c38 100644 --- a/src/kibana/plugins/discover/controllers/discover.js +++ b/src/kibana/plugins/discover/controllers/discover.js @@ -23,8 +23,6 @@ define(function (require) { require('services/timefilter'); require('components/highlight/highlight_tags'); - require('plugins/discover/directives/table'); - var app = require('modules').get('apps/discover', [ 'kibana/notify', 'kibana/courier', diff --git a/src/kibana/plugins/discover/index.html b/src/kibana/plugins/discover/index.html index 70dce657800629..7b0bf9a7d07ad3 100644 --- a/src/kibana/plugins/discover/index.html +++ b/src/kibana/plugins/discover/index.html @@ -154,23 +154,13 @@

Searching

fixed-scroll='table' fixed-scroll-trigger="state.columns"> - - - - - + infinite-scroll="true" + filter="filterQuery"> \ No newline at end of file diff --git a/src/kibana/plugins/dashboard/components/panel/panel.js b/src/kibana/plugins/dashboard/components/panel/panel.js index 90e3f1b44bd9cf..4c3397bb329f9f 100644 --- a/src/kibana/plugins/dashboard/components/panel/panel.js +++ b/src/kibana/plugins/dashboard/components/panel/panel.js @@ -1,5 +1,6 @@ define(function (require) { var moment = require('moment'); + var filterManager = require('components/filter_manager/filter_manager'); var $ = require('jquery'); require('modules') .get('app/dashboard') @@ -31,6 +32,12 @@ define(function (require) { $scope.savedObj = panelConfig.savedObj; $scope.edit = panelConfig.edit; $scope.$on('$destroy', panelConfig.savedObj.destroy); + + filterManager.init($state); + $scope.filter = function (field, value, operator) { + var index = $scope.savedObj.searchSource.get('index').id; + filterManager.add(field, value, operator, index); + }; }).catch(function (e) { $scope.error = e.message; }); From 7438cea7726a242ef031ffeb2a6241bc8f7d6853 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Tue, 6 Jan 2015 15:58:41 -0700 Subject: [PATCH 069/142] Add mouseover descriptions to each chart type. Closes #2541 --- .../components/visualize/visualize.less | 3 +++ src/kibana/plugins/metric_vis/metric_vis.js | 2 ++ src/kibana/plugins/table_vis/table_vis.js | 2 ++ src/kibana/plugins/vis_types/_vis_type.js | 1 + src/kibana/plugins/vis_types/vislib/area.js | 4 ++++ .../plugins/vis_types/vislib/histogram.js | 2 ++ src/kibana/plugins/vis_types/vislib/line.js | 2 ++ src/kibana/plugins/vis_types/vislib/pie.js | 2 ++ .../plugins/vis_types/vislib/tile_map.js | 2 ++ .../plugins/visualize/wizard/step_1.html | 20 +++++++++++++++++-- 10 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/visualize/visualize.less b/src/kibana/components/visualize/visualize.less index 89c1ff67ea8ea3..cda0e952dc6d7a 100644 --- a/src/kibana/components/visualize/visualize.less +++ b/src/kibana/components/visualize/visualize.less @@ -39,6 +39,9 @@ visualize { } +ul.visualizations .media-body { + font-size: 0.75em; +} visualize-spy { // this element should flex diff --git a/src/kibana/plugins/metric_vis/metric_vis.js b/src/kibana/plugins/metric_vis/metric_vis.js index bfa785daff61ff..6bc7d1b0bfdc4a 100644 --- a/src/kibana/plugins/metric_vis/metric_vis.js +++ b/src/kibana/plugins/metric_vis/metric_vis.js @@ -14,6 +14,8 @@ define(function (require) { return new TemplateVisType({ name: 'metric', title: 'Metric', + description: 'One big number for all of your one big number needs. Perfect for show ' + + 'a count of hits, or the exact average a numeric field', icon: 'fa-calculator', template: require('text!plugins/metric_vis/metric_vis.html'), params: { diff --git a/src/kibana/plugins/table_vis/table_vis.js b/src/kibana/plugins/table_vis/table_vis.js index 391f04d1675eb1..a3f677c97f5fb6 100644 --- a/src/kibana/plugins/table_vis/table_vis.js +++ b/src/kibana/plugins/table_vis/table_vis.js @@ -26,6 +26,8 @@ define(function (require) { name: 'table', title: 'Data table', icon: 'fa-table', + description: 'The data table provides a detailed breakdown, in tabular format, of the results of a composed ' + + 'aggregation. Tip, a data table is available from many other charts by clicking grey bar at the bottom of the chart', template: require('text!plugins/table_vis/table_vis.html'), params: { defaults: { diff --git a/src/kibana/plugins/vis_types/_vis_type.js b/src/kibana/plugins/vis_types/_vis_type.js index 97032118dcbfee..67cc17cb23d76d 100644 --- a/src/kibana/plugins/vis_types/_vis_type.js +++ b/src/kibana/plugins/vis_types/_vis_type.js @@ -10,6 +10,7 @@ define(function (require) { this.responseConverter = opts.responseConverter; this.hierarchicalData = opts.hierarchicalData || false; this.icon = opts.icon; + this.description = opts.description; this.schemas = opts.schemas || new VisTypeSchemas(); this.params = opts.params || {}; } diff --git a/src/kibana/plugins/vis_types/vislib/area.js b/src/kibana/plugins/vis_types/vislib/area.js index 3f6fb6c376b7e5..99b12a7f610635 100644 --- a/src/kibana/plugins/vis_types/vislib/area.js +++ b/src/kibana/plugins/vis_types/vislib/area.js @@ -7,6 +7,10 @@ define(function (require) { name: 'area', title: 'Area chart', icon: 'fa-area-chart', + description: 'Great for stacked timelines in which the total of all series is more important ' + + 'than comparing any two or more series. Less useful for assessing the relative change of ' + + 'unrelated data points as changes in a series lower down the stack will have a difficult to gauge ' + + 'effect on the series above it.', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/histogram.js b/src/kibana/plugins/vis_types/vislib/histogram.js index 2caae29849be18..cfc677b487e131 100644 --- a/src/kibana/plugins/vis_types/vislib/histogram.js +++ b/src/kibana/plugins/vis_types/vislib/histogram.js @@ -7,6 +7,8 @@ define(function (require) { name: 'histogram', title: 'Vertical bar chart', icon: 'fa-bar-chart', + description: 'The goto chart for oh-so-many needs. Great for time and non-time data. Stacked or grouped, ' + + 'exact numbers or percentages. If you are not sure which chart your need, you could do worse than to start here', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/line.js b/src/kibana/plugins/vis_types/vislib/line.js index 947da55c97f1e2..6ce2e8a39a0f0a 100644 --- a/src/kibana/plugins/vis_types/vislib/line.js +++ b/src/kibana/plugins/vis_types/vislib/line.js @@ -7,6 +7,8 @@ define(function (require) { name: 'line', title: 'Line chart', icon: 'fa-line-chart', + description: 'Often the best chart for high density time series. Great for comparing one series to another. ' + + 'Be careful with sparse sets as the connection between points can be misleading', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/pie.js b/src/kibana/plugins/vis_types/vislib/pie.js index fb566fdcf4d48a..029e588fa07a77 100644 --- a/src/kibana/plugins/vis_types/vislib/pie.js +++ b/src/kibana/plugins/vis_types/vislib/pie.js @@ -7,6 +7,8 @@ define(function (require) { name: 'pie', title: 'Pie chart', icon: 'fa-pie-chart', + description: 'Pie charts are ideal for displaying the parts of some whole. For example, sales percentages by department.' + + 'Pro Tip: Pie charts are best used sparingly, and with no more than 7 slices per pie', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/tile_map.js b/src/kibana/plugins/vis_types/vislib/tile_map.js index 343013b11211e2..f4b59719015eb0 100644 --- a/src/kibana/plugins/vis_types/vislib/tile_map.js +++ b/src/kibana/plugins/vis_types/vislib/tile_map.js @@ -8,6 +8,8 @@ define(function (require) { name: 'tile_map', title: 'Tile map', icon: 'fa-map-marker', + description: 'Your source for geographic maps. Requires an elasticsearch geo_point field. More specifically, a field ' + + 'that is mapped as type:geo_point with latitude and longitude coordinates.', params: { defaults: { mapType: 'Shaded Circle Markers', diff --git a/src/kibana/plugins/visualize/wizard/step_1.html b/src/kibana/plugins/visualize/wizard/step_1.html index 06d3f20d93619e..1a1a88f4481635 100644 --- a/src/kibana/plugins/visualize/wizard/step_1.html +++ b/src/kibana/plugins/visualize/wizard/step_1.html @@ -7,9 +7,25 @@

From a55c257f43e3898b723708d5b306c6b4d77b110e Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Tue, 6 Jan 2015 16:07:28 -0700 Subject: [PATCH 070/142] Include infinite scroll directive --- src/kibana/components/doc_table/doc_table.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/kibana/components/doc_table/doc_table.js b/src/kibana/components/doc_table/doc_table.js index e13061d1088730..b1454f371e661b 100644 --- a/src/kibana/components/doc_table/doc_table.js +++ b/src/kibana/components/doc_table/doc_table.js @@ -6,6 +6,7 @@ define(function (require) { require('css!components/doc_table/doc_table.css'); require('directives/truncated'); + require('directives/infinite_scroll'); require('components/doc_table/components/table_header'); require('components/doc_table/components/table_row'); @@ -54,12 +55,6 @@ define(function (require) { $scope.limit += 50; }; - // Set the watcher after initialization - $scope.$watchCollection('sorting', function (newSort, oldSort) { - // Don't react if sort values didn't really change - console.log(newSort); - }); - $scope.$watch('searchSource', prereq(function (searchSource) { if (!$scope.searchSource) return; From 65976b86b6b83440274dd42ed2392183b097b6c0 Mon Sep 17 00:00:00 2001 From: lukasolson Date: Tue, 6 Jan 2015 16:19:57 -0700 Subject: [PATCH 071/142] Standardize descriptions and justify icons --- src/kibana/plugins/metric_vis/metric_vis.js | 2 +- src/kibana/plugins/table_vis/table_vis.js | 2 +- src/kibana/plugins/vis_types/vislib/histogram.js | 2 +- src/kibana/plugins/vis_types/vislib/line.js | 2 +- src/kibana/plugins/vis_types/vislib/pie.js | 2 +- src/kibana/plugins/visualize/styles/main.less | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kibana/plugins/metric_vis/metric_vis.js b/src/kibana/plugins/metric_vis/metric_vis.js index 6bc7d1b0bfdc4a..c4f1caf0679488 100644 --- a/src/kibana/plugins/metric_vis/metric_vis.js +++ b/src/kibana/plugins/metric_vis/metric_vis.js @@ -15,7 +15,7 @@ define(function (require) { name: 'metric', title: 'Metric', description: 'One big number for all of your one big number needs. Perfect for show ' + - 'a count of hits, or the exact average a numeric field', + 'a count of hits, or the exact average a numeric field.', icon: 'fa-calculator', template: require('text!plugins/metric_vis/metric_vis.html'), params: { diff --git a/src/kibana/plugins/table_vis/table_vis.js b/src/kibana/plugins/table_vis/table_vis.js index a3f677c97f5fb6..3f5355acacfa26 100644 --- a/src/kibana/plugins/table_vis/table_vis.js +++ b/src/kibana/plugins/table_vis/table_vis.js @@ -27,7 +27,7 @@ define(function (require) { title: 'Data table', icon: 'fa-table', description: 'The data table provides a detailed breakdown, in tabular format, of the results of a composed ' + - 'aggregation. Tip, a data table is available from many other charts by clicking grey bar at the bottom of the chart', + 'aggregation. Tip, a data table is available from many other charts by clicking grey bar at the bottom of the chart.', template: require('text!plugins/table_vis/table_vis.html'), params: { defaults: { diff --git a/src/kibana/plugins/vis_types/vislib/histogram.js b/src/kibana/plugins/vis_types/vislib/histogram.js index cfc677b487e131..be99dc4b01ac89 100644 --- a/src/kibana/plugins/vis_types/vislib/histogram.js +++ b/src/kibana/plugins/vis_types/vislib/histogram.js @@ -8,7 +8,7 @@ define(function (require) { title: 'Vertical bar chart', icon: 'fa-bar-chart', description: 'The goto chart for oh-so-many needs. Great for time and non-time data. Stacked or grouped, ' + - 'exact numbers or percentages. If you are not sure which chart your need, you could do worse than to start here', + 'exact numbers or percentages. If you are not sure which chart your need, you could do worse than to start here.', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/line.js b/src/kibana/plugins/vis_types/vislib/line.js index 6ce2e8a39a0f0a..9d42b94229728b 100644 --- a/src/kibana/plugins/vis_types/vislib/line.js +++ b/src/kibana/plugins/vis_types/vislib/line.js @@ -8,7 +8,7 @@ define(function (require) { title: 'Line chart', icon: 'fa-line-chart', description: 'Often the best chart for high density time series. Great for comparing one series to another. ' + - 'Be careful with sparse sets as the connection between points can be misleading', + 'Be careful with sparse sets as the connection between points can be misleading.', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/vis_types/vislib/pie.js b/src/kibana/plugins/vis_types/vislib/pie.js index 029e588fa07a77..077414bba523c1 100644 --- a/src/kibana/plugins/vis_types/vislib/pie.js +++ b/src/kibana/plugins/vis_types/vislib/pie.js @@ -8,7 +8,7 @@ define(function (require) { title: 'Pie chart', icon: 'fa-pie-chart', description: 'Pie charts are ideal for displaying the parts of some whole. For example, sales percentages by department.' + - 'Pro Tip: Pie charts are best used sparingly, and with no more than 7 slices per pie', + 'Pro Tip: Pie charts are best used sparingly, and with no more than 7 slices per pie.', params: { defaults: { shareYAxis: true, diff --git a/src/kibana/plugins/visualize/styles/main.less b/src/kibana/plugins/visualize/styles/main.less index a42dac8a4885c0..945b52df8158e1 100644 --- a/src/kibana/plugins/visualize/styles/main.less +++ b/src/kibana/plugins/visualize/styles/main.less @@ -13,7 +13,7 @@ .visualizations .visualization i { margin-right: @padding-base-horizontal; font-size: 1.5em; - width: 1em; + width: 1.5em; } .visualizations { From b2d8172d930d6c36a8775e916a24296b98ef3b9f Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 05:54:36 -0700 Subject: [PATCH 072/142] update elasticsearch client --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index ca1e772735e24d..6d8942ba62f0b1 100644 --- a/bower.json +++ b/bower.json @@ -32,7 +32,7 @@ "bluebird": "~2.1.3", "bootstrap": "~3.3.1", "d3": "~3.4.8", - "elasticsearch": "elasticsearch/bower-elasticsearch-js#prerelease", + "elasticsearch": "~3.1.1", "Faker": "~1.1.0", "FileSaver": "*", "font-awesome": "~4.2.0", From 2919104744ab8958d844c949e17ced0016e2cef0 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 06:22:21 -0700 Subject: [PATCH 073/142] ensure that agg ids are always strings --- src/kibana/components/vis/_agg_config.js | 6 +-- test/unit/specs/components/vis/_agg_config.js | 40 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index ef49691be5804b..2ba030e5b591ca 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -6,7 +6,7 @@ define(function (require) { function AggConfig(vis, opts) { var self = this; - self.id = opts.id || AggConfig.nextId(vis.aggs); + self.id = String(opts.id || AggConfig.nextId(vis.aggs)); self.vis = vis; self._opts = opts = (opts || {}); @@ -42,7 +42,7 @@ define(function (require) { var nextId = AggConfig.nextId(have); haveNot.forEach(function (obj) { - obj.id = nextId++; + obj.id = String(nextId++); }); return list; @@ -55,7 +55,7 @@ define(function (require) { */ AggConfig.nextId = function (list) { return 1 + list.reduce(function (max, obj) { - return Math.max(max, obj.id || 0); + return Math.max(max, +obj.id || 0); }, 0); }; diff --git a/test/unit/specs/components/vis/_agg_config.js b/test/unit/specs/components/vis/_agg_config.js index 99475ade6ead2b..78e2dd3862b909 100644 --- a/test/unit/specs/components/vis/_agg_config.js +++ b/test/unit/specs/components/vis/_agg_config.js @@ -113,42 +113,42 @@ define(function (require) { {} ]; AggConfig.ensureIds(objs); - expect(objs[0]).to.have.property('id', 1); - expect(objs[1]).to.have.property('id', 2); - expect(objs[2]).to.have.property('id', 3); - expect(objs[3]).to.have.property('id', 4); + expect(objs[0]).to.have.property('id', '1'); + expect(objs[1]).to.have.property('id', '2'); + expect(objs[2]).to.have.property('id', '3'); + expect(objs[3]).to.have.property('id', '4'); }); it('assigns ids relative to the other items in the list', function () { var objs = [ - { id: 100 }, + { id: '100' }, {}, ]; AggConfig.ensureIds(objs); - expect(objs[0]).to.have.property('id', 100); - expect(objs[1]).to.have.property('id', 101); + expect(objs[0]).to.have.property('id', '100'); + expect(objs[1]).to.have.property('id', '101'); }); it('assigns ids relative to the other items in the list', function () { var objs = [ - { id: 100 }, - { id: 200 }, - { id: 500 }, - { id: 350 }, + { id: '100' }, + { id: '200' }, + { id: '500' }, + { id: '350' }, {}, ]; AggConfig.ensureIds(objs); - expect(objs[0]).to.have.property('id', 100); - expect(objs[1]).to.have.property('id', 200); - expect(objs[2]).to.have.property('id', 500); - expect(objs[3]).to.have.property('id', 350); - expect(objs[4]).to.have.property('id', 501); + expect(objs[0]).to.have.property('id', '100'); + expect(objs[1]).to.have.property('id', '200'); + expect(objs[2]).to.have.property('id', '500'); + expect(objs[3]).to.have.property('id', '350'); + expect(objs[4]).to.have.property('id', '501'); }); it('uses ::nextId to get the starting value', function () { sinon.stub(AggConfig, 'nextId').returns(534); var objs = AggConfig.ensureIds([{}]); - expect(objs[0]).to.have.property('id', 534); + expect(objs[0]).to.have.property('id', '534'); }); it('only calls ::nextId once', function () { @@ -158,7 +158,7 @@ define(function (require) { expect(AggConfig.nextId).to.have.property('callCount', 1); objs.forEach(function (obj, i) { - expect(obj).to.have.property('id', start + i); + expect(obj).to.have.property('id', String(start + i)); }); }); }); @@ -194,13 +194,13 @@ define(function (require) { }); var aggConfig = vis.aggs.byTypeName.date_histogram[0]; - expect(aggConfig.id).to.be(1); + expect(aggConfig.id).to.be('1'); expect(aggConfig.params).to.be.an('object'); expect(aggConfig.type).to.be.an(AggType).and.have.property('name', 'date_histogram'); expect(aggConfig.schema).to.be.an('object').and.have.property('name', 'segment'); var state = aggConfig.toJSON(); - expect(state).to.have.property('id', 1); + expect(state).to.have.property('id', '1'); expect(state.params).to.be.an('object'); expect(state).to.have.property('type', 'date_histogram'); expect(state).to.have.property('schema', 'segment'); From a2c0b98f1d7264f068e0c157838b03ab6b6b5b69 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 06:32:44 -0700 Subject: [PATCH 074/142] [visualize/editor/terms] orderAgg id extends termsAgg id so it is always unique --- src/kibana/components/agg_types/buckets/terms.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index d24ebc00664314..485cabfcac5afb 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -68,8 +68,14 @@ define(function (require) { return orderAgg.toJSON(); }, deserialize: function (state, agg) { + return this.makeOrderAgg(agg, state); + }, + makeOrderAgg: function (termsAgg, state) { + state = state || {}; state.schema = orderAggSchema; - return new AggConfig(agg.vis, state); + var orderAgg = new AggConfig(termsAgg.vis, state); + orderAgg.id = termsAgg.id + '-orderAgg'; + return orderAgg; }, controller: function ($scope) { $scope.safeMakeLabel = function (agg) { @@ -91,6 +97,7 @@ define(function (require) { var aggs = agg.vis.aggs; var params = agg.params; var orderBy = params.orderBy; + var paramDef = agg.type.params.byName.orderAgg; // setup the initial value of orderBy if (!orderBy && prevOrderBy === INIT) { @@ -113,9 +120,7 @@ define(function (require) { return; } - params.orderAgg = params.orderAgg || new AggConfig(agg.vis, { - schema: orderAggSchema - }); + params.orderAgg = params.orderAgg || paramDef.makeOrderAgg(agg); } }, write: function (agg, output) { From fda057262500a20d8118f86cb4496a94eb7c12c4 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 06:49:09 -0700 Subject: [PATCH 075/142] [visualize/editor] limit replace:true so directive boundries are more clear --- src/kibana/plugins/visualize/editor/agg.js | 1 - .../plugins/visualize/editor/agg_group.js | 1 - .../plugins/visualize/editor/editor.html | 2 +- .../plugins/visualize/editor/sidebar.html | 68 +++++++++---------- .../plugins/visualize/editor/sidebar.js | 1 - .../visualize/editor/styles/editor.less | 8 +++ .../plugins/visualize/editor/vis_options.js | 1 - 7 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/agg.js b/src/kibana/plugins/visualize/editor/agg.js index 943fe94a2349a1..1858f4581139ce 100644 --- a/src/kibana/plugins/visualize/editor/agg.js +++ b/src/kibana/plugins/visualize/editor/agg.js @@ -16,7 +16,6 @@ define(function (require) { return { restrict: 'E', - replace: true, template: require('text!plugins/visualize/editor/agg.html'), link: function ($scope, $el) { $scope.editorOpen = $scope.agg.brandNew; diff --git a/src/kibana/plugins/visualize/editor/agg_group.js b/src/kibana/plugins/visualize/editor/agg_group.js index 0e491e9100ad52..c2f273618f6376 100644 --- a/src/kibana/plugins/visualize/editor/agg_group.js +++ b/src/kibana/plugins/visualize/editor/agg_group.js @@ -11,7 +11,6 @@ define(function (require) { return { restrict: 'E', template: require('text!plugins/visualize/editor/agg_group.html'), - replace: true, scope: true, link: function ($scope, $el, attr) { $scope.groupName = attr.groupName; diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html index 3a4e60b1b22b8b..94621dac30b8a7 100644 --- a/src/kibana/plugins/visualize/editor/editor.html +++ b/src/kibana/plugins/visualize/editor/editor.html @@ -97,7 +97,7 @@
- +
diff --git a/src/kibana/plugins/visualize/editor/sidebar.html b/src/kibana/plugins/visualize/editor/sidebar.html index 3ed3d9278d0908..99200a17848949 100644 --- a/src/kibana/plugins/visualize/editor/sidebar.html +++ b/src/kibana/plugins/visualize/editor/sidebar.html @@ -1,39 +1,37 @@ -
- \ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/sidebar.js b/src/kibana/plugins/visualize/editor/sidebar.js index 9e6eace60e8177..ae3145617665a7 100644 --- a/src/kibana/plugins/visualize/editor/sidebar.js +++ b/src/kibana/plugins/visualize/editor/sidebar.js @@ -10,7 +10,6 @@ define(function (require) { return { restrict: 'E', template: require('text!plugins/visualize/editor/sidebar.html'), - replace: true, scope: true, link: function ($scope) { $scope.$bind('vis', 'editableVis'); diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index 7c4353173fe47c..47a85fbecedfe8 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -274,6 +274,14 @@ } } +vis-editor, +vis-editor-agg-group, +vis-editor-agg, +vis-editor-agg-params, +vis-editor-agg-param, +vis-editor-vis-options { + .flex-parent(); +} form.vis-share { div.form-control { diff --git a/src/kibana/plugins/visualize/editor/vis_options.js b/src/kibana/plugins/visualize/editor/vis_options.js index eccb6a87aaf0cf..882dc088e2211d 100644 --- a/src/kibana/plugins/visualize/editor/vis_options.js +++ b/src/kibana/plugins/visualize/editor/vis_options.js @@ -8,7 +8,6 @@ define(function (require) { return { restrict: 'E', template: require('text!plugins/visualize/editor/vis_options.html'), - replace: true, scope: { vis: '=', }, From 5564cbb8dd91d7867e085c1ae8101ddce9224d13 Mon Sep 17 00:00:00 2001 From: Juan Thomassie Date: Wed, 7 Jan 2015 10:34:27 -0600 Subject: [PATCH 076/142] added min-height, min-width to flex items, fixes #1873 --- .../components/vislib/styles/_layout.less | 28 ++++++++++++++++++- .../components/vislib/styles/_legend.less | 3 ++ .../visualize/editor/styles/editor.less | 4 +++ src/kibana/styles/_mixins.less | 5 +++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/vislib/styles/_layout.less b/src/kibana/components/vislib/styles/_layout.less index 3cb0c17a83f23e..aff41515f9c1c2 100644 --- a/src/kibana/components/vislib/styles/_layout.less +++ b/src/kibana/components/vislib/styles/_layout.less @@ -3,25 +3,33 @@ .visualize-chart { .display(flex); .flex(1 1 100%); + min-height: 0; + min-width: 0; } .vis-wrapper { .display(flex); .flex(1 1 100%); .flex-direction(row); - margin: 10px 0 0 6px; + // margin: 10px 0 0 6px; + min-height: 0; + min-width: 0; } /* YAxis logic */ .y-axis-col-wrapper { .display(flex); .flex-direction(column); + min-height: 0; + min-width: 0; } .y-axis-col { .display(flex); .flex-direction(row); .flex(1 0 36px); + min-height: 0; + min-width: 0; } .y-axis-spacer-block { @@ -33,6 +41,7 @@ .flex-direction(column); width: 38px; min-height: 20px; + min-width: 0; } .y-axis-div { @@ -50,6 +59,7 @@ .display(flex); .flex-direction(column); min-height: 14px; + min-width: 0; width: 14px; } @@ -72,6 +82,8 @@ .display(flex); .flex(1 0 20px); .flex-direction(column); + min-height: 0; + min-width: 0; } .chart-wrapper { @@ -79,22 +91,30 @@ .flex(1 0 20px); overflow: visible; margin: 0 5px 0 0; + min-height: 0; + min-width: 0; } .chart-wrapper-column { .display(flex); .flex(1 0 20px); .flex-direction(row); + min-height: 0; + min-width: 0; } .chart-wrapper-row { .display(flex); .flex-direction(column); .flex(1 0 100%); + min-height: 0; + min-width: 0; } .chart { .flex(1 1 100%); + min-height: 0; + min-width: 0; > svg { display: block; @@ -105,16 +125,21 @@ .chart-row { .flex(1 1 auto); + min-height: 0; + min-width: 0; } .chart-column { .flex(1 1 auto); + min-height: 0; + min-width: 0; } .x-axis-wrapper { .display(flex); .flex-direction(column); min-height: 45px; + min-width: 0; overflow: visible; } @@ -122,6 +147,7 @@ .display(flex); .flex-direction(row); min-height: 15px; + min-width: 0; } .x-axis-chart-title { diff --git a/src/kibana/components/vislib/styles/_legend.less b/src/kibana/components/vislib/styles/_legend.less index d2907c487ffd33..209462c2db4deb 100644 --- a/src/kibana/components/vislib/styles/_legend.less +++ b/src/kibana/components/vislib/styles/_legend.less @@ -6,6 +6,7 @@ overflow-x: hidden; overflow-y: auto; min-width: 40px; + min-height: 0; .header { width: 100%; @@ -21,6 +22,8 @@ visibility: visible; .display(flex); .flex-direction(column); + min-height: 0; + min-width: 0; li.color { min-height: 22px; diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index 7c4353173fe47c..d5fe8eb8846555 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -245,6 +245,8 @@ .display(flex); .flex-direction(column); overflow: auto; + min-height: 0; + min-width: 0; &.embedded { .flex-shrink(1); @@ -270,6 +272,8 @@ .visualize-chart { .flex(1, 0, 100%); position: relative; + min-height: 0; + min-width: 0; } } } diff --git a/src/kibana/styles/_mixins.less b/src/kibana/styles/_mixins.less index b8ccc1346bdadd..0b449a9996fa82 100644 --- a/src/kibana/styles/_mixins.less +++ b/src/kibana/styles/_mixins.less @@ -2,9 +2,12 @@ .flex(@grow, @shrink, @basis); .display(flex); .flex-direction(column); - + min-height: 0; + min-width: 0; > * { .flex-shrink(0); + min-height: 0; + min-width: 0; } } From edfa33d15aefba3a8f388b91bda3b40257d594d3 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 07:23:16 -0700 Subject: [PATCH 077/142] [$watchMulti] added collection and deep equality watching --- src/kibana/components/watch_multi.js | 95 ++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/src/kibana/components/watch_multi.js b/src/kibana/components/watch_multi.js index ed1195e2c96bfd..f0e5dbcb075c4f 100644 --- a/src/kibana/components/watch_multi.js +++ b/src/kibana/components/watch_multi.js @@ -10,7 +10,26 @@ define(function (require) { * with making code simpler it also merges all of the watcher * handlers within a single tick. * - * @param {array[string|function]} expressions - the list of expressions to $watch + * # expression format + * expressions can be specified in one of the following ways: + * 1. string that evaluates to a value on scope. Creates a regular $watch + * expression. + * 'someScopeValue.prop' === $scope.$watch('someScopeValue.prop', fn); + * + * 2. #1 prefixed with '[]', which uses $watchCollection rather than $watch. + * '[]expr' === $scope.$watchCollection('expr', fn); + * + * 3. #1 prefixed with '=', which uses $watch with objectEquality turned on + * '=expr' === $scope.$watch('expr', fn, true); + * + * 4. a function that will be called, like a normal function water + * + * 5. an object with any of the properties: + * `get`: the getter called on each itteration + * `deep`: a flag to turn on objectEquality in $watch + * `fn`: the watch registration function ($scope.$watch or $scope.$watchCollection) + * + * @param {array[string|function|obj]} expressions - the list of expressions to $watch * @param {Function} fn - the callback function * @param {boolean} deep - should the watchers be created as deep watchers? * @return {undefined} @@ -20,31 +39,53 @@ define(function (require) { if (!_.isFunction(fn)) throw new TypeError('expexted a function that is triggered on each watch'); var $scope = this; - var initQueue = _.clone(expressions); var fired = false; - var vals = { - new: new Array(expressions.length), - old: new Array(expressions.length) - }; + var queue = []; + var vals = new Array(expressions.length); + var prev = new Array(expressions.length); + + function normalizeExpression(expr) { + if (!expr) return; + + var norm = { + fn: $scope.$watch, + deep: false + }; + + if (_.isFunction(expr)) return _.assign(norm, { get: expr }); + if (_.isObject(expr)) return _.assign(norm, expr); + if (!_.isString(expr)) return; + + if (expr.substr(0, 2) === '[]') { + return _.assign(norm, { + fn: $scope.$watchCollection, + get: expr.substr(2) + }); + } + + if (expr.charAt(0) === '=') { + return _.assign(norm, { + deep: true, + get: expr.substr(1) + }); + } + + return _.assign(norm, { get: expr }); + } expressions.forEach(function (expr, i) { - $scope.$watch(expr, function (newVal, oldVal) { - vals.new[i] = newVal; - - if (initQueue) { - vals.old[i] = oldVal; - - var qIdx = initQueue.indexOf(expr); - if (qIdx !== -1) initQueue.splice(qIdx, 1); - if (initQueue.length === 0) { - initQueue = false; - if (fn.length) { - fn(vals.new.slice(0), vals.old.slice(0)); - } else { - fn(); - } - } - return; + expr = normalizeExpression(expr); + if (!expr) return; + + queue.push(expr); + expr.fn.call($scope, expr.get, function (newVal, oldVal) { + vals[i] = newVal; + + if (queue) { + prev[i] = oldVal; + _.pull(queue, expr); + if (queue.length > 0) return; + queue = false; } if (fired) return; @@ -53,16 +94,16 @@ define(function (require) { fired = false; if (fn.length) { - fn(vals.new.slice(0), vals.old.slice(0)); + fn(vals.slice(0), prev.slice(0)); } else { fn(); } - for (var i = 0; i < vals.new.length; i++) { - vals.old[i] = vals.new[i]; + for (var i = 0; i < vals.length; i++) { + prev[i] = vals[i]; } }); - }); + }, expr.deep); }); }; From 93552bf2db81db46f0e9c527d9adb8e3828177a6 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 08:40:12 -0700 Subject: [PATCH 078/142] [visualize/editor] update add-agg form to match new vis wizard --- src/kibana/plugins/visualize/editor/agg.html | 13 +++++--- src/kibana/plugins/visualize/editor/agg.js | 1 + .../plugins/visualize/editor/agg_add.html | 29 ++++++++++++++++++ .../plugins/visualize/editor/agg_add.js | 28 +++++++++++++++++ .../plugins/visualize/editor/agg_group.html | 30 ++----------------- .../plugins/visualize/editor/agg_group.js | 21 ++----------- .../visualize/editor/styles/editor.less | 22 +++++++------- 7 files changed, 83 insertions(+), 61 deletions(-) create mode 100644 src/kibana/plugins/visualize/editor/agg_add.html create mode 100644 src/kibana/plugins/visualize/editor/agg_add.js diff --git a/src/kibana/plugins/visualize/editor/agg.html b/src/kibana/plugins/visualize/editor/agg.html index d510f92fbef73d..56a1c0e732d49d 100644 --- a/src/kibana/plugins/visualize/editor/agg.html +++ b/src/kibana/plugins/visualize/editor/agg.html @@ -1,4 +1,4 @@ - +
@@ -30,7 +30,7 @@
\ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg_add.js b/src/kibana/plugins/visualize/editor/agg_add.js new file mode 100644 index 00000000000000..4540cee0314e3f --- /dev/null +++ b/src/kibana/plugins/visualize/editor/agg_add.js @@ -0,0 +1,28 @@ +define(function (require) { + require('modules') + .get('kibana') + .directive('visEditorAggAdd', function (Private) { + var AggConfig = Private(require('components/vis/_agg_config')); + + return { + restrict: 'E', + template: require('text!plugins/visualize/editor/agg_add.html'), + controllerAs: 'add', + controller: function ($scope) { + var self = this; + + self.form = false; + self.submit = function (schema) { + self.form = false; + + var aggConfig = new AggConfig($scope.vis, { + schema: schema + }); + aggConfig.brandNew = true; + + $scope.vis.aggs.push(aggConfig); + }; + } + }; + }); +}); \ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg_group.html b/src/kibana/plugins/visualize/editor/agg_group.html index ffab37022f8e46..b3dcbe9aa2bc04 100644 --- a/src/kibana/plugins/visualize/editor/agg_group.html +++ b/src/kibana/plugins/visualize/editor/agg_group.html @@ -14,35 +14,9 @@ - +
-
- - -
- - +
\ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg_group.js b/src/kibana/plugins/visualize/editor/agg_group.js index c2f273618f6376..372e75ac592e0c 100644 --- a/src/kibana/plugins/visualize/editor/agg_group.js +++ b/src/kibana/plugins/visualize/editor/agg_group.js @@ -3,11 +3,9 @@ define(function (require) { .get('app/visualize') .directive('visEditorAggGroup', function (Private) { require('plugins/visualize/editor/agg'); + require('plugins/visualize/editor/agg_add'); require('plugins/visualize/editor/nesting_indicator'); - var eachGroupHtml = require('text!plugins/visualize/editor/agg_group.html'); - var AggConfig = Private(require('components/vis/_agg_config')); - return { restrict: 'E', template: require('text!plugins/visualize/editor/agg_group.html'), @@ -17,12 +15,9 @@ define(function (require) { $scope.$bind('group', 'vis.aggs.bySchemaGroup["' + $scope.groupName + '"]'); $scope.$bind('schemas', 'vis.type.schemas["' + $scope.groupName + '"]'); - // "sub-scope" for the add form to use - $scope.addForm = {}; - $scope.$watchMulti([ 'schemas', - 'group.length' + '[]group' ], function () { var stats = $scope.stats = { min: 0, @@ -36,9 +31,7 @@ define(function (require) { stats.min += schema.min; stats.max += schema.max; }); - }); - $scope.$watchCollection('group', function () { $scope.availableSchema = $scope.schemas.filter(function (schema) { var count = 0; @@ -52,16 +45,6 @@ define(function (require) { if (count < schema.max) return true; }); }); - - $scope.createUsingSchema = function (schema) { - $scope.addForm = {}; - - var aggConfig = new AggConfig($scope.vis, { - schema: schema - }); - aggConfig.brandNew = true; - $scope.vis.aggs.push(aggConfig); - }; } }; diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index 47a85fbecedfe8..2ce260eb544f86 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -127,6 +127,7 @@ .display(flex); .align-items(center); .flex(1, 0, auto); + margin-bottom: @vis-editor-agg-editor-spacing; &-toggle { .flex(0, 0, auto); @@ -168,8 +169,6 @@ } &-editor { - margin-top: @vis-editor-agg-editor-spacing; - &-ranges { td { padding: 0 @vis-editor-agg-editor-spacing @vis-editor-agg-editor-spacing 0; @@ -221,14 +220,17 @@ .border-radius(0); } - &-add-form { - margin: @vis-editor-agg-editor-spacing * 3; - padding: @vis-editor-agg-editor-spacing; - > button { - display: block; - text-align: left; - width: 100%; - margin: 0 0 5px 0; + &-add { + .flex-parent(); + + &-subagg { + margin-bottom: -@vis-editor-agg-editor-spacing - 1; // extra one pixel covers the aggs bottom border + margin-right: -@vis-editor-agg-editor-spacing; + margin-left: -@vis-editor-agg-editor-spacing; + } + + &-schemas { + margin: @vis-editor-agg-editor-spacing * 3; } } From 597ceb764e7b0ec739738ac9c65e99a79aa8baeb Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 08:40:58 -0700 Subject: [PATCH 079/142] [visualize/editor] clean up some outdated references --- .../agg_types/controls/extended_bounds.html | 6 +++--- src/kibana/plugins/visualize/editor/agg_params.js | 13 +------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/kibana/components/agg_types/controls/extended_bounds.html b/src/kibana/components/agg_types/controls/extended_bounds.html index 7502cb47033eef..b85a6c6f8f522f 100644 --- a/src/kibana/components/agg_types/controls/extended_bounds.html +++ b/src/kibana/components/agg_types/controls/extended_bounds.html @@ -1,4 +1,4 @@ -
+
@@ -7,7 +7,7 @@
Min (optional)
@@ -15,7 +15,7 @@
Max (optional)
diff --git a/src/kibana/plugins/visualize/editor/agg_params.js b/src/kibana/plugins/visualize/editor/agg_params.js index 1b2f548a55b9ed..0f2ca8713090d5 100644 --- a/src/kibana/plugins/visualize/editor/agg_params.js +++ b/src/kibana/plugins/visualize/editor/agg_params.js @@ -32,7 +32,7 @@ define(function (require) { if ($scope.agg.schema.editor) { $schemaEditor.append($scope.agg.schema.editor); - $compile($schemaEditor)(editorScope()); + $compile($schemaEditor)($scope.$new()); } // allow selection of an aggregation @@ -135,17 +135,6 @@ define(function (require) { return fields; } - // generic child scope creation, for both schema and agg - function editorScope() { - var $editorScope = $scope.$new(); - - setupBoundProp($editorScope, 'agg.type', 'aggType'); - setupBoundProp($editorScope, 'agg', 'aggConfig'); - setupBoundProp($editorScope, 'agg.params', 'params'); - - return $editorScope; - } - // bind a property from our scope a child scope, with one-way binding function setupBoundProp($child, get, set) { var getter = _.partial($parse(get), $scope); From 64b9f37c5530ab1634b20b052dc864e607e5c893 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 10:15:53 -0700 Subject: [PATCH 080/142] [aggTypes/terms] support old states which do not have an orderAgg --- src/kibana/components/agg_types/buckets/terms.js | 2 +- src/kibana/components/vis/_agg_configs.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index 485cabfcac5afb..22133ad900e44c 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -130,7 +130,7 @@ define(function (require) { var orderAgg = agg.params.orderAgg || vis.aggs.getResponseAggById(agg.params.orderBy); - if (orderAgg.type.name === 'count') { + if (!orderAgg || orderAgg.type.name === 'count') { order._count = dir; return; } diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index 26489df9b51e72..fabb991cf2aca9 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -133,7 +133,8 @@ define(function (require) { * @return {AggConfig} */ AggConfigs.prototype.getResponseAggById = function (id) { - var parts = String(id).split('.'); + id = String(id); + var parts = id.split('.'); if (parts.length === 1) { return this.byId[id]; } From 90ef122e581f32b4d698cc5882d6505616ddef93 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 10:18:31 -0700 Subject: [PATCH 081/142] [visualize/wizard] remove flickering and hover effect --- src/kibana/plugins/visualize/styles/main.less | 47 ++++++++++++++----- .../plugins/visualize/wizard/step_1.html | 32 ++++--------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/kibana/plugins/visualize/styles/main.less b/src/kibana/plugins/visualize/styles/main.less index 945b52df8158e1..bf475921c43ff6 100644 --- a/src/kibana/plugins/visualize/styles/main.less +++ b/src/kibana/plugins/visualize/styles/main.less @@ -1,8 +1,4 @@ -@import (reference) "../../../styles/_mixins.less"; -@import (reference) "../../../styles/_bootstrap.less"; -@import (reference) "../../../styles/theme/_theme.less"; -@import (reference) "../../../styles/_variables.less"; -@import (reference) "lesshat.less"; +@import (reference) "../../../styles/main.less"; .vis-wizard { h1 { @@ -10,14 +6,40 @@ } } -.visualizations .visualization i { - margin-right: @padding-base-horizontal; - font-size: 1.5em; - width: 1.5em; -} +.wizard-vis-type { + .list-group-item(); + .list-group-menu .list-group-menu-item(); + + // overrided for tablet and desktop + @media (min-width: @screen-md-min) { + .display(flex); + .align-items(flex-start); + } -.visualizations { - font-size: 1.2em; + &-heading { + .flex(0 0 200px); + .display(flex); + .align-items(center); + font-size: 1.2em; + + .fa { + .flex(0 0 auto); + margin-right: @padding-base-horizontal; + font-size: 1.5em; + width: 1em; + text-align: center; + } + + h4 { + .flex(1 0 auto); + } + } + + &-description { + .flex(1 1 auto); + margin-top: -5px; + margin-bottom: -5px; + } } .visualize-info { @@ -32,7 +54,6 @@ font-weight: bold; } - } @import "../editor/styles/editor.less"; diff --git a/src/kibana/plugins/visualize/wizard/step_1.html b/src/kibana/plugins/visualize/wizard/step_1.html index 1a1a88f4481635..37ae5c34d2e5a3 100644 --- a/src/kibana/plugins/visualize/wizard/step_1.html +++ b/src/kibana/plugins/visualize/wizard/step_1.html @@ -4,31 +4,17 @@

Step 1

- +

Or, open a saved visualization

From 8b3590071070be28bf600c3cd26a6a77c6dd7c2d Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 10:49:25 -0700 Subject: [PATCH 082/142] [editor/nestingIndicator] simplify --- .../visualize/editor/nesting_indicator.js | 45 +++++-------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/nesting_indicator.js b/src/kibana/plugins/visualize/editor/nesting_indicator.js index c7c379362f3ec0..c27c6e336ead0c 100644 --- a/src/kibana/plugins/visualize/editor/nesting_indicator.js +++ b/src/kibana/plugins/visualize/editor/nesting_indicator.js @@ -3,24 +3,8 @@ define(function (require) { .get('kibana') .directive('nestingIndicator', function ($rootScope, $parse, Private) { var _ = require('lodash'); - var angular = require('angular'); - var ruleBase = 'border-left-'; - - var getColor = (function () { - var i = 0; - var colorPool = Private(require('components/vislib/components/color/color_palette'))(100); - var assigned = {}; - return function (item) { - var key = item.id || item.$$hashKey; - if (!key) throw new Error('expected an item that is part of an ngRepeat'); - - if (!assigned[key]) { - assigned[key] = colorPool[i++ % colorPool.length]; - } - - return assigned[key]; - }; - }()); + var $ = require('jquery'); + var getColors = Private(require('components/vislib/components/color/color_palette')); return { restrict: 'E', @@ -29,27 +13,18 @@ define(function (require) { list: '=' }, link: function ($scope, $el, attr) { - $scope.$watchCollection('list', function () { if (!$scope.list || !$scope.item) return; var item = $scope.item; - var list = $scope.list; - var bars = $scope.bars = []; - - for (var i = 0; i <= list.length; i++) { - var color = getColor(list[i]); - - bars.push( - angular - .element('') - .css('background-color', color) - ); - - if (list[i] === $scope.item) break; - } - - $el.html(bars); + var index = $scope.list.indexOf($scope.item); + var bars = $scope.list.slice(0, index + 1); + var colors = getColors(bars.length); + + $el.html(bars.map(function (item, i) { + return $(document.createElement('span')) + .css('background-color', colors[i]); + })); }); } }; From a4fb49268694465b3e9d9bb216ac618c35ec64c2 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 7 Jan 2015 10:59:41 -0700 Subject: [PATCH 083/142] Deduping the list of indexes --- src/kibana/components/index_patterns/_mapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/index_patterns/_mapper.js b/src/kibana/components/index_patterns/_mapper.js index 1b9f76a864da7d..520ded4614c3b7 100644 --- a/src/kibana/components/index_patterns/_mapper.js +++ b/src/kibana/components/index_patterns/_mapper.js @@ -92,7 +92,7 @@ define(function (require) { } else { return key; } - }).flatten().value().sort(); + }).flatten().uniq().value().sort(); var matches = all.filter(function (existingIndex) { var parsed = moment(existingIndex, indexPattern.id); From 4c136bd7b9c6ae6017f2314ee28f1ab4245f4386 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 11:25:14 -0700 Subject: [PATCH 084/142] firefox takes flex-shrink:0 very seriously --- src/kibana/components/vislib/styles/_layout.less | 2 +- src/kibana/plugins/visualize/editor/styles/editor.less | 8 ++------ src/kibana/styles/_mixins.less | 5 +---- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/kibana/components/vislib/styles/_layout.less b/src/kibana/components/vislib/styles/_layout.less index aff41515f9c1c2..2a6f4f63914184 100644 --- a/src/kibana/components/vislib/styles/_layout.less +++ b/src/kibana/components/vislib/styles/_layout.less @@ -106,7 +106,7 @@ .chart-wrapper-row { .display(flex); .flex-direction(column); - .flex(1 0 100%); + .flex(1 1 100%); min-height: 0; min-width: 0; } diff --git a/src/kibana/plugins/visualize/editor/styles/editor.less b/src/kibana/plugins/visualize/editor/styles/editor.less index d5fe8eb8846555..9ee67100c37695 100644 --- a/src/kibana/plugins/visualize/editor/styles/editor.less +++ b/src/kibana/plugins/visualize/editor/styles/editor.less @@ -245,8 +245,6 @@ .display(flex); .flex-direction(column); overflow: auto; - min-height: 0; - min-width: 0; &.embedded { .flex-shrink(1); @@ -266,14 +264,12 @@ visualize { .flex-parent(); - .flex(1, 0, auto); + .flex(1, 1, 100%); } .visualize-chart { - .flex(1, 0, 100%); + .flex(1, 1, 100%); position: relative; - min-height: 0; - min-width: 0; } } } diff --git a/src/kibana/styles/_mixins.less b/src/kibana/styles/_mixins.less index 0b449a9996fa82..b8ccc1346bdadd 100644 --- a/src/kibana/styles/_mixins.less +++ b/src/kibana/styles/_mixins.less @@ -2,12 +2,9 @@ .flex(@grow, @shrink, @basis); .display(flex); .flex-direction(column); - min-height: 0; - min-width: 0; + > * { .flex-shrink(0); - min-height: 0; - min-width: 0; } } From ee768338f24b0fe9ce735a8284aaa2ef30c88925 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Wed, 7 Jan 2015 13:23:19 -0700 Subject: [PATCH 085/142] use index for sort indicators instead of title --- src/kibana/components/paginated_table/paginated_table.html | 6 +++--- src/kibana/components/paginated_table/paginated_table.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/kibana/components/paginated_table/paginated_table.html b/src/kibana/components/paginated_table/paginated_table.html index e193222deb2458..1deb49d92dcba3 100644 --- a/src/kibana/components/paginated_table/paginated_table.html +++ b/src/kibana/components/paginated_table/paginated_table.html @@ -17,9 +17,9 @@ ng-if="col.sortable !== false" class="fa" ng-class="{ - 'fa-sort-asc': paginatedTable.sort.columnName === col.title && paginatedTable.sort.direction === 'asc', - 'fa-sort-desc': paginatedTable.sort.columnName === col.title && paginatedTable.sort.direction === 'desc', - 'fa-sort': paginatedTable.sort.direction === null || paginatedTable.sort.columnName !== col.title + 'fa-sort-asc': paginatedTable.sort.columnIndex === $index && paginatedTable.sort.direction === 'asc', + 'fa-sort-desc': paginatedTable.sort.columnIndex === $index && paginatedTable.sort.direction === 'desc', + 'fa-sort': paginatedTable.sort.columnIndex !== $index || paginatedTable.sort.direction === null }"> diff --git a/src/kibana/components/paginated_table/paginated_table.js b/src/kibana/components/paginated_table/paginated_table.js index 8a8f892f15536c..bef3dc08cceb35 100644 --- a/src/kibana/components/paginated_table/paginated_table.js +++ b/src/kibana/components/paginated_table/paginated_table.js @@ -43,6 +43,7 @@ define(function (require) { sortDirection = directions[self.sort.direction]; } + self.sort.columnIndex = colIndex; self.sort.columnName = col.title; self.sort.direction = sortDirection; self._setSortGetter(colIndex); From 7e07e88d28139c73d692c5ec944c50b0459b1374 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Wed, 7 Jan 2015 13:28:29 -0700 Subject: [PATCH 086/142] test re-org, add test for sorting icons on duplicate columns --- .../specs/components/paginated_table/index.js | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/test/unit/specs/components/paginated_table/index.js b/test/unit/specs/components/paginated_table/index.js index 30e679ebc2282d..15e7e4d6d4c0f2 100644 --- a/test/unit/specs/components/paginated_table/index.js +++ b/test/unit/specs/components/paginated_table/index.js @@ -212,12 +212,39 @@ define(function (require) { expect(tableRows.eq(lastRowIndex).find('td').eq(1).text()).to.be('zzzz'); }); - it('should handle sorting on columns with the same name', function () { - data.columns = []; - for (var i = 0; i < data.rows[0].length; i++) { - data.columns.push({ title: 'test row' }); - } + }); + + describe('sorting duplicate columns', function () { + var data; + var paginatedTable; + var colText = 'test row'; + + beforeEach(function () { + var cols = [ + { title: colText }, + { title: colText }, + { title: colText } + ]; + var rows = [ + ['bbbb', 'aaaa', 'zzzz'], + ['cccc', 'cccc', 'aaaa'], + ['zzzz', 'bbbb', 'bbbb'], + ['aaaa', 'zzzz', 'cccc'], + ]; + data = makeData(cols, rows); + renderTable(data.columns, data.rows); + paginatedTable = $el.isolateScope().paginatedTable; + }); + + it('should should have duplicate column titles', function () { + var columns = $el.find('thead th span'); + columns.each(function () { + expect(this.innerText).to.be(colText); + }); + }); + + it('should handle sorting on columns with the same name', function () { // sort by the last column paginatedTable.sortColumn(2); $scope.$digest(); @@ -230,6 +257,17 @@ define(function (require) { expect(tableRows.eq(2).find('td').eq(2).text()).to.be('cccc'); expect(tableRows.eq(3).find('td').eq(2).text()).to.be('zzzz'); }); + + it('should not sort duplicate columns', function () { + paginatedTable.sortColumn(1); + $scope.$digest(); + + var sorters = $el.find('thead th i'); + expect(sorters.eq(0).hasClass('fa-sort')).to.be(true); + expect(sorters.eq(1).hasClass('fa-sort')).to.be(false); + expect(sorters.eq(2).hasClass('fa-sort')).to.be(true); + }); + }); describe('custom sorting', function () { From acec0ecf194362a3ec7960466157b40752aaee06 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Wed, 7 Jan 2015 13:42:20 -0700 Subject: [PATCH 087/142] Add 'no results found message' --- .../components/doc_table/doc_table.html | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/kibana/components/doc_table/doc_table.html b/src/kibana/components/doc_table/doc_table.html index a56dd5e31966c7..446bbe948ae4f2 100644 --- a/src/kibana/components/doc_table/doc_table.html +++ b/src/kibana/components/doc_table/doc_table.html @@ -1,5 +1,25 @@ - - +
+ +
+ + + + + +
+
+ + -
- - - - - - - - -
- \ No newline at end of file + +
+
+

+

No results found

+
\ No newline at end of file From ea7064ce2af6ac9feac52f6637e2c41d2c3825be Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Wed, 7 Jan 2015 13:56:59 -0700 Subject: [PATCH 088/142] Crank results so we have hits --- test/unit/specs/components/doc_table/doc_table.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit/specs/components/doc_table/doc_table.js b/test/unit/specs/components/doc_table/doc_table.js index 4940b017dd5813..0c915c0eab789a 100644 --- a/test/unit/specs/components/doc_table/doc_table.js +++ b/test/unit/specs/components/doc_table/doc_table.js @@ -101,6 +101,9 @@ define(function (require) { }); it('should have a header and a table element', function () { + searchSource.crankResults(); + $scope.$digest(); + expect($elem.find('thead').length).to.be(1); expect($elem.find('table').length).to.be(1); }); From e5fe084c6ff68e223be007958347e4ad46a8c31e Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 13:57:03 -0700 Subject: [PATCH 089/142] only read the response for non-aborted requests --- .../components/courier/fetch/_call_response_handlers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/courier/fetch/_call_response_handlers.js b/src/kibana/components/courier/fetch/_call_response_handlers.js index e76f7b1fda63fc..62a53b88c0b297 100644 --- a/src/kibana/components/courier/fetch/_call_response_handlers.js +++ b/src/kibana/components/courier/fetch/_call_response_handlers.js @@ -9,12 +9,12 @@ define(function (require) { function callResponseHandlers(requests, responses) { return Promise.map(requests, function (req, i) { - var resp = responses[i]; - if (req === ABORTED || req.aborted) { return ABORTED; } + var resp = responses[i]; + if (resp.timed_out) { notify.warning(new SearchTimeout()); } From 8ac478a06f30f97c6c4a0bb1305a92d698f084e0 Mon Sep 17 00:00:00 2001 From: lukasolson Date: Wed, 7 Jan 2015 16:15:41 -0700 Subject: [PATCH 090/142] Make style changes as per Rashid's suggestions --- src/kibana/plugins/markdown_vis/markdown_vis.js | 1 + src/kibana/plugins/visualize/styles/main.less | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kibana/plugins/markdown_vis/markdown_vis.js b/src/kibana/plugins/markdown_vis/markdown_vis.js index 7c4d9aa98003b5..379f48aca5edc0 100644 --- a/src/kibana/plugins/markdown_vis/markdown_vis.js +++ b/src/kibana/plugins/markdown_vis/markdown_vis.js @@ -14,6 +14,7 @@ define(function (require) { name: 'markdown', title: 'Markdown widget', icon: 'fa-code', + description: 'Useful for displaying explanations or instructions for dashboards.', template: require('text!plugins/markdown_vis/markdown_vis.html'), params: { editor: require('text!plugins/markdown_vis/markdown_vis_params.html') diff --git a/src/kibana/plugins/visualize/styles/main.less b/src/kibana/plugins/visualize/styles/main.less index bf475921c43ff6..3794155447260c 100644 --- a/src/kibana/plugins/visualize/styles/main.less +++ b/src/kibana/plugins/visualize/styles/main.less @@ -37,8 +37,7 @@ &-description { .flex(1 1 auto); - margin-top: -5px; - margin-bottom: -5px; + color: @brand-primary; } } From 89f15493f2689836773755c52d747bb936a52581 Mon Sep 17 00:00:00 2001 From: Joe Fleming Date: Wed, 7 Jan 2015 17:30:35 -0700 Subject: [PATCH 091/142] fix reference to colName sorting, add test --- .../paginated_table/paginated_table.js | 2 +- .../specs/components/paginated_table/index.js | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/kibana/components/paginated_table/paginated_table.js b/src/kibana/components/paginated_table/paginated_table.js index bef3dc08cceb35..5490f8da3eaf82 100644 --- a/src/kibana/components/paginated_table/paginated_table.js +++ b/src/kibana/components/paginated_table/paginated_table.js @@ -32,7 +32,7 @@ define(function (require) { var sortDirection; - if (self.sort.columnName !== col.title) { + if (self.sort.columnIndex !== colIndex) { sortDirection = 'asc'; } else { var directions = { diff --git a/test/unit/specs/components/paginated_table/index.js b/test/unit/specs/components/paginated_table/index.js index 15e7e4d6d4c0f2..5d6fb6c4fe2e3e 100644 --- a/test/unit/specs/components/paginated_table/index.js +++ b/test/unit/specs/components/paginated_table/index.js @@ -258,6 +258,30 @@ define(function (require) { expect(tableRows.eq(3).find('td').eq(2).text()).to.be('zzzz'); }); + it('should sort correctly between columns', function () { + // sort by the last column + paginatedTable.sortColumn(2); + $scope.$digest(); + + var tableRows = $el.find('tbody tr'); + expect(tableRows.eq(0).find('td').eq(0).text()).to.be('cccc'); + expect(tableRows.eq(0).find('td').eq(1).text()).to.be('cccc'); + expect(tableRows.eq(0).find('td').eq(2).text()).to.be('aaaa'); + + // sort by the first column + paginatedTable.sortColumn(0); + $scope.$digest(); + + tableRows = $el.find('tbody tr'); + expect(tableRows.eq(0).find('td').eq(0).text()).to.be('aaaa'); + expect(tableRows.eq(0).find('td').eq(1).text()).to.be('zzzz'); + expect(tableRows.eq(0).find('td').eq(2).text()).to.be('cccc'); + + expect(tableRows.eq(1).find('td').eq(0).text()).to.be('bbbb'); + expect(tableRows.eq(2).find('td').eq(0).text()).to.be('cccc'); + expect(tableRows.eq(3).find('td').eq(0).text()).to.be('zzzz'); + }); + it('should not sort duplicate columns', function () { paginatedTable.sortColumn(1); $scope.$digest(); From 4f3257472231e8ad4206949cd1824951f4104ae6 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 7 Jan 2015 17:47:02 -0700 Subject: [PATCH 092/142] fix old ref to aggConfig --- src/kibana/components/agg_types/controls/extended_bounds.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/agg_types/controls/extended_bounds.html b/src/kibana/components/agg_types/controls/extended_bounds.html index 7502cb47033eef..c3fdb3f9f4b20f 100644 --- a/src/kibana/components/agg_types/controls/extended_bounds.html +++ b/src/kibana/components/agg_types/controls/extended_bounds.html @@ -1,4 +1,4 @@ -
+
From cd3171ac6184f57947593f75bb5c3c0eefc74b95 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Wed, 7 Jan 2015 21:37:44 -0700 Subject: [PATCH 093/142] Add filtering for scripted fields --- .../components/doc_viewer/doc_viewer.html | 4 +-- .../components/filter_bar/lib/mapFilter.js | 1 + .../filter_manager/filter_manager.js | 28 +++++++++++++++---- .../index_patterns/_index_pattern.js | 2 +- .../field_chooser/discover_field_details.html | 4 +-- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/kibana/components/doc_viewer/doc_viewer.html b/src/kibana/components/doc_viewer/doc_viewer.html index e8917667055a29..ed5a44a864df29 100644 --- a/src/kibana/components/doc_viewer/doc_viewer.html +++ b/src/kibana/components/doc_viewer/doc_viewer.html @@ -15,8 +15,8 @@ - - + + diff --git a/src/kibana/components/filter_bar/lib/mapFilter.js b/src/kibana/components/filter_bar/lib/mapFilter.js index 3d7037d7015f33..11078469648340 100644 --- a/src/kibana/components/filter_bar/lib/mapFilter.js +++ b/src/kibana/components/filter_bar/lib/mapFilter.js @@ -26,6 +26,7 @@ define(function (require) { Private(require('./mapExists')), Private(require('./mapMissing')), Private(require('./mapQueryString')), + Private(require('./mapScript')), Private(require('./mapDefault')) // ProTip: last one to get applied ]; diff --git a/src/kibana/components/filter_manager/filter_manager.js b/src/kibana/components/filter_manager/filter_manager.js index 0230dca8f0edde..ede139c03116fc 100644 --- a/src/kibana/components/filter_manager/filter_manager.js +++ b/src/kibana/components/filter_manager/filter_manager.js @@ -11,6 +11,10 @@ define(function (require) { values = _.isArray(values) ? values : [values]; + // Have we been passed a simple name or an actual field object? + + var fieldName = _.isObject(field) ? field.name : field; + var negate = operation === '-'; var filters = _.flatten([self.$state.filters], true); @@ -19,12 +23,12 @@ define(function (require) { var existing = _.find(filters, function (filter) { if (!filter) return; - if (field === '_exists_' && filter.exists) { + if (fieldName === '_exists_' && filter.exists) { return filter.exists.field === value; } if (filter.query) { - return filter.query.match[field] && filter.query.match[field].query === value; + return filter.query.match[fieldName] && filter.query.match[fieldName].query === value; } }); @@ -35,14 +39,28 @@ define(function (require) { return; } - switch (field) { + switch (fieldName) { case '_exists_': filters.push({ meta: { negate: negate, index: index }, exists: { field: value } }); break; default: - var filter = { meta: { negate: negate, index: index }, query: { match: {} } }; - filter.query.match[field] = { query: value, type: 'phrase' }; + var filter; + if (field.scripted) { + filter = { + meta: { negate: negate, index: index, field: fieldName }, + script: { + script: '(' + field.script + ') == value', + params: { + value: value + } + } + }; + } else { + filter = { meta: { negate: negate, index: index }, query: { match: {} } }; + filter.query.match[fieldName] = { query: value, type: 'phrase' }; + } filters.push(filter); + break; } }); diff --git a/src/kibana/components/index_patterns/_index_pattern.js b/src/kibana/components/index_patterns/_index_pattern.js index 95d0f3e09527ec..d98f53aa6e82db 100644 --- a/src/kibana/components/index_patterns/_index_pattern.js +++ b/src/kibana/components/index_patterns/_index_pattern.js @@ -104,7 +104,7 @@ define(function (require) { } }, filterable: { - value: field.name === '_id' || (field.indexed && type.filterable) + value: field.name === '_id' || ((field.indexed && type.filterable) || field.scripted) }, format: { get: function () { diff --git a/src/kibana/plugins/discover/components/field_chooser/discover_field_details.html b/src/kibana/plugins/discover/components/field_chooser/discover_field_details.html index a4e7216b6e2f13..29c5d374f57795 100644 --- a/src/kibana/plugins/discover/components/field_chooser/discover_field_details.html +++ b/src/kibana/plugins/discover/components/field_chooser/discover_field_details.html @@ -19,9 +19,9 @@
Quick Count
+ ng-click="updateFilterInQuery(field, bucket.value, '-')"> + ng-click="updateFilterInQuery(field, bucket.value, '+')">
{{bucket.value}} From f8d2c3bbfbe088d51d5925c69a7ed9bf7713c33d Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 07:49:46 -0700 Subject: [PATCH 094/142] Add mapScript --- .../components/filter_bar/lib/mapScript.js | 20 ++++++++ .../specs/components/filter_bar/mapScript.js | 50 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/kibana/components/filter_bar/lib/mapScript.js create mode 100644 test/unit/specs/components/filter_bar/mapScript.js diff --git a/src/kibana/components/filter_bar/lib/mapScript.js b/src/kibana/components/filter_bar/lib/mapScript.js new file mode 100644 index 00000000000000..c391514caf174b --- /dev/null +++ b/src/kibana/components/filter_bar/lib/mapScript.js @@ -0,0 +1,20 @@ +define(function (require) { + var _ = require('lodash'); + return function mapScriptProvider(Promise, courier) { + return function (filter) { + var key, value, field; + if (filter.script) { + return courier + .indexPatterns + .get(filter.meta.index).then(function (indexPattern) { + key = filter.meta.field; + field = indexPattern.fields.byName[key]; + value = filter.script.params.value; + value = field.format.convert(value); + return { key: key, value: value }; + }); + } + return Promise.reject(filter); + }; + }; +}); diff --git a/test/unit/specs/components/filter_bar/mapScript.js b/test/unit/specs/components/filter_bar/mapScript.js new file mode 100644 index 00000000000000..d44aaade1f6bd1 --- /dev/null +++ b/test/unit/specs/components/filter_bar/mapScript.js @@ -0,0 +1,50 @@ +/* global sinon */ +define(function (require) { + describe('Filter Bar Directive', function () { + describe('mapScript()', function () { + + var indexPattern, mapScript, $rootScope, getIndexPatternStub; + beforeEach(module('kibana')); + + beforeEach(function () { + getIndexPatternStub = sinon.stub(); + module('kibana/courier', function ($provide) { + $provide.service('courier', function () { + var courier = { indexPatterns: { get: getIndexPatternStub } }; + return courier; + }); + }); + }); + + beforeEach(inject(function (Private, _$rootScope_, Promise) { + $rootScope = _$rootScope_; + mapScript = Private(require('components/filter_bar/lib/mapScript')); + indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); + getIndexPatternStub.returns(Promise.resolve(indexPattern)); + })); + + it('should return the key and value for matching filters', function (done) { + var filter = { + meta: { index: 'logstash-*', field: 'scritped number' }, + script: { script: 'doc["scritped number"].value * 5', params: { value: 35}} + }; + mapScript(filter).then(function (result) { + expect(result).to.have.property('key', 'scritped number'); + expect(result).to.have.property('value', 35); + done(); + }); + $rootScope.$apply(); + }); + + it('should return undefined for none matching', function (done) { + var filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } }; + mapScript(filter).catch(function (result) { + expect(result).to.be(filter); + done(); + }); + $rootScope.$apply(); + }); + + }); + }); +}); \ No newline at end of file From 67bfae158cbbe4b0aee688efa2894a3ca5da368e Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 08:27:36 -0700 Subject: [PATCH 095/142] Add not_analyzed warning to visualize, hint at available .raw field --- .../components/agg_types/controls/field.html | 13 +++++++++++++ .../plugins/visualize/editor/agg_params.js | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/kibana/components/agg_types/controls/field.html b/src/kibana/components/agg_types/controls/field.html index d8de0beaf1987e..5a50010387d468 100644 --- a/src/kibana/components/agg_types/controls/field.html +++ b/src/kibana/components/agg_types/controls/field.html @@ -9,4 +9,17 @@ ng-model="agg.params.field" ng-options="field as field.displayName group by field.type for field in indexedFields"> + +

+ Careful! The field selected contains analyzed strings. Values such as foo-bar will be broken into foo and bar. See Mapping Core Types for more information on setting this field as not_analyzed +

+ +

+ Tip: {{agg.params.field.name + '.raw'}} may be a not_analyzed version of this field. +

+
+ + +

+
\ No newline at end of file diff --git a/src/kibana/plugins/visualize/editor/agg_params.js b/src/kibana/plugins/visualize/editor/agg_params.js index 3d2b4bd8122092..1fc4b6e10272a3 100644 --- a/src/kibana/plugins/visualize/editor/agg_params.js +++ b/src/kibana/plugins/visualize/editor/agg_params.js @@ -1,4 +1,6 @@ define(function (require) { + var IndexedArray = require('utils/indexed_array/index'); + require('modules') .get('app/visualize', ['ui.select']) .directive('visEditorAggParams', function ($compile, $parse, Private, Notifier, $filter) { @@ -134,7 +136,19 @@ define(function (require) { fields = $filter('orderBy')(fields, ['type', 'name']); } - return fields; + return new IndexedArray({ + + /** + * @type {Array} + */ + index: ['name'], + + /** + * [group description] + * @type {Array} + */ + initialSet: fields + }); } // generic child scope creation, for both schema and agg From e9fe0d4c6e10e05478fcdac4bf6c95e6dece1bee Mon Sep 17 00:00:00 2001 From: lukasolson Date: Thu, 8 Jan 2015 08:53:17 -0700 Subject: [PATCH 096/142] Remove columnName in paginated table sorting as it is no longer used --- src/kibana/components/paginated_table/paginated_table.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/kibana/components/paginated_table/paginated_table.js b/src/kibana/components/paginated_table/paginated_table.js index 5490f8da3eaf82..8bb916e290af1f 100644 --- a/src/kibana/components/paginated_table/paginated_table.js +++ b/src/kibana/components/paginated_table/paginated_table.js @@ -20,7 +20,7 @@ define(function (require) { controller: function ($scope) { var self = this; self.sort = { - columnName: null, + columnIndex: null, direction: null }; @@ -44,7 +44,6 @@ define(function (require) { } self.sort.columnIndex = colIndex; - self.sort.columnName = col.title; self.sort.direction = sortDirection; self._setSortGetter(colIndex); }; From 749748fefd346cbd6ee76669724d6c7a0291c81c Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 8 Jan 2015 08:45:44 -0700 Subject: [PATCH 097/142] update lodash-deep --- bower.json | 2 +- src/kibana/require.config.js | 2 +- src/kibana/utils/_mixins.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 6d8942ba62f0b1..e69a4908385490 100644 --- a/bower.json +++ b/bower.json @@ -48,7 +48,7 @@ "require-css": "~0.1.2", "requirejs": "~2.1.10", "requirejs-text": "~2.0.10", - "lodash-deep": "spenceralger/lodash-deep#a2768a72d7", + "lodash-deep": "spenceralger/lodash-deep#compat", "marked": "~0.3.2" }, "devDependencies": {} diff --git a/src/kibana/require.config.js b/src/kibana/require.config.js index 6f0d7b5cf38c90..3c30a04e65d4bf 100644 --- a/src/kibana/require.config.js +++ b/src/kibana/require.config.js @@ -29,7 +29,7 @@ require.config({ jquery: 'bower_components/jquery/dist/jquery', leaflet: 'bower_components/leaflet/dist/leaflet', lodash_src: 'bower_components/lodash/dist/lodash', - 'lodash-deep': 'bower_components/lodash-deep/lodash-deep', + 'lodash-deep': 'bower_components/lodash-deep/factory', moment: 'bower_components/moment/moment', 'ng-clip': 'bower_components/ng-clip/src/ngClip', text: 'bower_components/requirejs-text/text', diff --git a/src/kibana/utils/_mixins.js b/src/kibana/utils/_mixins.js index c6742629a48c99..7efe206c22a9a1 100644 --- a/src/kibana/utils/_mixins.js +++ b/src/kibana/utils/_mixins.js @@ -10,7 +10,7 @@ define(function (require) { * of lodash. */ var _ = require('lodash_src'); - _.mixin(require('lodash-deep')); + require('lodash-deep')(_); _.mixin(require('utils/_mixins_chainable'), { chain: true }); _.mixin(require('utils/_mixins_notchainable'), { chain: false }); From 7e976342aa3cf7309823aa741db9b060336e2cf6 Mon Sep 17 00:00:00 2001 From: Francois Valdy Date: Thu, 8 Jan 2015 17:07:42 +0100 Subject: [PATCH 098/142] Fix unique id used in track by _id field unicity is only guaranteed per index+type, having the same _id for 2 distinct types in an index was giving angular errors in the UI. --- src/kibana/components/doc_table/doc_table.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kibana/components/doc_table/doc_table.html b/src/kibana/components/doc_table/doc_table.html index 446bbe948ae4f2..16c90632a194e4 100644 --- a/src/kibana/components/doc_table/doc_table.html +++ b/src/kibana/components/doc_table/doc_table.html @@ -8,7 +8,7 @@ sorting="sorting"> - -

No results found

-
\ No newline at end of file +
From d59ecc60c4fae81ec35ed4c3259c6a7b56a86e41 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 8 Jan 2015 13:00:42 -0700 Subject: [PATCH 099/142] fix reference to old params obj --- src/kibana/plugins/vis_types/controls/rows_or_columns.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kibana/plugins/vis_types/controls/rows_or_columns.html b/src/kibana/plugins/vis_types/controls/rows_or_columns.html index 2c83de4b718496..a2394ae72de06c 100644 --- a/src/kibana/plugins/vis_types/controls/rows_or_columns.html +++ b/src/kibana/plugins/vis_types/controls/rows_or_columns.html @@ -3,14 +3,14 @@ From f165319aba015fbd96a6cb060fab44495ba8e52d Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 8 Jan 2015 13:01:31 -0700 Subject: [PATCH 100/142] [aggConfig] wrap sub agg ids that have periods --- .../agg_types/metrics/_get_response_agg_config.js | 8 +++++++- src/kibana/components/vis/_agg_configs.js | 10 +++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/kibana/components/agg_types/metrics/_get_response_agg_config.js b/src/kibana/components/agg_types/metrics/_get_response_agg_config.js index aca0018d168232..10c319f50fe61a 100644 --- a/src/kibana/components/agg_types/metrics/_get_response_agg_config.js +++ b/src/kibana/components/agg_types/metrics/_get_response_agg_config.js @@ -30,7 +30,13 @@ define(function (require) { function ResponseAggConfig(key) { this.key = key; this.parentId = this.id; - this.id = this.parentId + '.' + key; + + var subId = String(key); + if (subId.indexOf('.') > -1) { + this.id = this.parentId + '[\'' + subId.replace(/'/g, '\\\'') + '\']'; + } else { + this.id = this.parentId + '.' + subId; + } } ResponseAggConfig.prototype = Object.create(parentAgg, { diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index fabb991cf2aca9..a1069849a24c0f 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -133,13 +133,9 @@ define(function (require) { * @return {AggConfig} */ AggConfigs.prototype.getResponseAggById = function (id) { - id = String(id); - var parts = id.split('.'); - if (parts.length === 1) { - return this.byId[id]; - } - - var reqAgg = this.byId[parts[0]]; + var reqAgg = _.find(this.getRequestAggs(), function (agg) { + return id.substr(0, agg.id.length) === agg.id; + }); return _.find(reqAgg.getResponseAggs(), { id: id }); }; From 165c3b05a64880010fcdf7627e3ce4be96fa41c0 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 16:45:05 -0700 Subject: [PATCH 101/142] Add reference to index pattern from field --- src/kibana/components/index_patterns/_index_pattern.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kibana/components/index_patterns/_index_pattern.js b/src/kibana/components/index_patterns/_index_pattern.js index d98f53aa6e82db..5f725bdd7dc03a 100644 --- a/src/kibana/components/index_patterns/_index_pattern.js +++ b/src/kibana/components/index_patterns/_index_pattern.js @@ -112,6 +112,9 @@ define(function (require) { return formatName ? fieldFormats.byName[formatName] : fieldFormats.defaultByType[field.type]; } }, + indexPattern: { + value: self + }, sortable: { value: field.indexed && type.sortable }, From 29a1c69f05d7415aad7ba41bbb5b84094588f8e6 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 16:45:36 -0700 Subject: [PATCH 102/142] workaround for elasticsearch always returning string on scripted terms agg --- src/kibana/components/agg_types/buckets/terms.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/kibana/components/agg_types/buckets/terms.js b/src/kibana/components/agg_types/buckets/terms.js index c9f4088de24572..ced8d55adb0aee 100644 --- a/src/kibana/components/agg_types/buckets/terms.js +++ b/src/kibana/components/agg_types/buckets/terms.js @@ -99,6 +99,13 @@ define(function (require) { orderAgg = agg.vis.aggs.byId[agg.params.orderBy]; } + // TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings + // thus causing issues with filtering. This probably causes other issues since float might not + // be able to contain the number on the elasticsearch side + if (output.params.script) { + output.params.valueType = agg.field().type === 'number' ? 'float' : agg.field().type; + } + if (orderAgg.type.name === 'count') { order._count = dir; } else { From 8106ffedf5c9038ce9b494b23916df48dd0fec15 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 16:46:19 -0700 Subject: [PATCH 103/142] Abstract filter builders from agg filters --- .../buckets/create_filter/date_histogram.js | 9 +++-- .../buckets/create_filter/filters.js | 8 ++--- .../buckets/create_filter/histogram.js | 10 +++--- .../agg_types/buckets/create_filter/range.js | 10 +++--- .../agg_types/buckets/create_filter/terms.js | 9 ++--- .../components/filter_manager/lib/phrase.js | 23 +++++++++++++ .../components/filter_manager/lib/query.js | 11 +++++++ .../components/filter_manager/lib/range.js | 33 +++++++++++++++++++ 8 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 src/kibana/components/filter_manager/lib/phrase.js create mode 100644 src/kibana/components/filter_manager/lib/query.js create mode 100644 src/kibana/components/filter_manager/lib/range.js diff --git a/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js b/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js index fa8bc4abc55539..285ec321680f4c 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js +++ b/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js @@ -1,19 +1,18 @@ define(function (require) { var moment = require('moment'); var interval = require('utils/interval'); + var buildRangeFilter = require('components/filter_manager/lib/range'); return function createDateHistogramFilterProvider(Private) { var calculateInterval = Private(require('components/agg_types/param_types/_calculate_interval')); return function (aggConfig, key) { var result = calculateInterval(aggConfig); var date = moment(key).add(result.interval, 'ms'); - var filter = { meta: {}, range: {} }; - filter.range[aggConfig.params.field.name] = { + + return buildRangeFilter(aggConfig.params.field, { gte: parseInt(key, 10), lte: date.valueOf() - }; - filter.meta.index = aggConfig.vis.indexPattern.id; - return filter; + }); }; }; diff --git a/src/kibana/components/agg_types/buckets/create_filter/filters.js b/src/kibana/components/agg_types/buckets/create_filter/filters.js index 43f3bb8dc10a84..ba263ec61dda79 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/filters.js +++ b/src/kibana/components/agg_types/buckets/create_filter/filters.js @@ -1,4 +1,5 @@ define(function (require) { + var buildFilterQuery = require('components/filter_manager/lib/query'); var _ = require('lodash'); return function CreateFilterFiltersProvider(Private) { return function (aggConfig, key) { @@ -7,12 +8,7 @@ define(function (require) { var filter = dslFilters[key]; if (filter) { - return { - query: filter.query, - meta: { - index: aggConfig.vis.indexPattern.id - } - }; + return buildFilterQuery(filter.query, aggConfig.vis.indexPattern.id); } }; }; diff --git a/src/kibana/components/agg_types/buckets/create_filter/histogram.js b/src/kibana/components/agg_types/buckets/create_filter/histogram.js index 9b8f55dee3ce8e..b0c7d9ea380d89 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/histogram.js +++ b/src/kibana/components/agg_types/buckets/create_filter/histogram.js @@ -1,14 +1,14 @@ define(function (require) { + var buildRangeFilter = require('components/filter_manager/lib/range'); + return function createHistogramFitlerProvider(Private) { return function (aggConfig, key) { var value = parseInt(key, 10); - var filter = { meta: {}, range: {} }; - filter.range[aggConfig.params.field.name] = { + + return buildRangeFilter(aggConfig.params.field, { gte: value, lt: value + aggConfig.params.interval - }; - filter.meta.index = aggConfig.vis.indexPattern.id; - return filter; + }); }; }; }); diff --git a/src/kibana/components/agg_types/buckets/create_filter/range.js b/src/kibana/components/agg_types/buckets/create_filter/range.js index 1de6ccf28f6ca9..845e561acea0d3 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/range.js +++ b/src/kibana/components/agg_types/buckets/create_filter/range.js @@ -1,16 +1,14 @@ define(function (require) { - return function createRangeFilterPrivider(Private) { + var buildRangeFilter = require('components/filter_manager/lib/range'); + return function createRangeFilterProvider(Private) { return function (aggConfig, key) { - var filter = { meta: {}, range: {} }; var splits = key.split(/\-/); var gte = Number(splits[0]); var lte = Number(splits[1]); - filter.range[aggConfig.params.field.name] = { + return buildRangeFilter(aggConfig.params.field, { gte: gte, lte: lte - }; - filter.meta.index = aggConfig.vis.indexPattern.id; - return filter; + }); }; }; }); diff --git a/src/kibana/components/agg_types/buckets/create_filter/terms.js b/src/kibana/components/agg_types/buckets/create_filter/terms.js index 86eb7be6952c6d..ba81fb02ae1315 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/terms.js +++ b/src/kibana/components/agg_types/buckets/create_filter/terms.js @@ -1,13 +1,8 @@ define(function (require) { + var buildPhraseQuery = require('components/filter_manager/lib/phrase'); return function createTermsFilterProvider(Private) { return function (aggConfig, key) { - var filter = { meta: {}, query: { match: {} } }; - filter.query.match[aggConfig.params.field.name] = { - query: key, - type: 'phrase' - }; - filter.meta.index = aggConfig.vis.indexPattern.id; - return filter; + return buildPhraseQuery(aggConfig.params.field, key); }; }; }); diff --git a/src/kibana/components/filter_manager/lib/phrase.js b/src/kibana/components/filter_manager/lib/phrase.js new file mode 100644 index 00000000000000..e78c93b84c6e67 --- /dev/null +++ b/src/kibana/components/filter_manager/lib/phrase.js @@ -0,0 +1,23 @@ +define(function (require) { + var _ = require('lodash'); + return function buildPhraseFilter(field, value) { + var filter = { meta: { index: field.indexPattern.id} }; + + if (field.scripted) { + filter.script = { + script: '(' + field.script + ') == value', + params: { + value: value + } + }; + filter.meta.field = field.name; + } else { + filter.query = { match: {} }; + filter.query.match[field.name] = { + query: value, + type: 'phrase' + }; + } + return filter; + }; +}); \ No newline at end of file diff --git a/src/kibana/components/filter_manager/lib/query.js b/src/kibana/components/filter_manager/lib/query.js new file mode 100644 index 00000000000000..9d4d53df544135 --- /dev/null +++ b/src/kibana/components/filter_manager/lib/query.js @@ -0,0 +1,11 @@ +define(function (require) { + var _ = require('lodash'); + return function buildPhraseFilter(query, index) { + return { + query: query, + meta: { + index: index + } + }; + }; +}); \ No newline at end of file diff --git a/src/kibana/components/filter_manager/lib/range.js b/src/kibana/components/filter_manager/lib/range.js new file mode 100644 index 00000000000000..cbf0cb0f862e06 --- /dev/null +++ b/src/kibana/components/filter_manager/lib/range.js @@ -0,0 +1,33 @@ +define(function (require) { + var _ = require('lodash'); + return function buildRangeFilter(field, params) { + var filter = { meta: { index: field.indexPattern.id} }; + + if (params.gte && params.gt) throw new Error('gte and gt are mutually exclusive'); + if (params.lte && params.lt) throw new Error('lte and lt are mutually exclusive'); + + if (field.scripted) { + var operators = { + gt: '>', + gte: '>=', + lte: '<=', + lt: '<', + }; + + var script = _.map(params, function (value, key) { + return '(' + field.script + ')' + operators[key] + key; + }).join(' && '); + + var value = _.map(params, function (value, key) { + return '+' + operators[key] + value; + }).join(' '); + + filter.script = { script: script, params: params }; + filter.script.params.value = value; + filter.meta.field = field.name; + } else { + filter.range[field.name] = params; + } + return filter; + }; +}); \ No newline at end of file From 99c3f009923ccd64de7ff3eb32e6ce89b6050886 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 8 Jan 2015 16:49:20 -0700 Subject: [PATCH 104/142] [aggTypes/percentile] split the percents into individual inputs --- .../agg_types/controls/_percent_list.js | 161 ++++++++++++++---- .../agg_types/controls/percents.html | 30 +++- 2 files changed, 155 insertions(+), 36 deletions(-) diff --git a/src/kibana/components/agg_types/controls/_percent_list.js b/src/kibana/components/agg_types/controls/_percent_list.js index 8f2e0cd442e777..61b52f056ea9ed 100644 --- a/src/kibana/components/agg_types/controls/_percent_list.js +++ b/src/kibana/components/agg_types/controls/_percent_list.js @@ -1,4 +1,5 @@ define(function (require) { + var $ = require('jquery'); var _ = require('lodash'); var INVALID = {}; // invalid flag @@ -6,49 +7,151 @@ define(function (require) { require('modules') .get('kibana') - .directive('percentList', function () { + .directive('percentList', function ($parse) { return { restrict: 'A', require: 'ngModel', - link: function ($scope, $el, attrs, ngModelCntr) { - function parse(viewValue) { - if (!_.isString(viewValue)) return INVALID; + link: function ($scope, $el, attrs, ngModelController) { + var $repeater = $el.closest('[ng-repeat]'); + var $listGetter = $parse(attrs.percentList); + + var namedKeys = { + 13: 'enter', + 38: 'up', + 40: 'down', + 8: 'delete', + 46: 'delete' + }; + + var handlers = { + 'up': change(add, 1), + 'shift-up': change(addTenth, 1), + + 'down': change(add, -1), + 'shift-down': change(addTenth, -1), + + 'enter': function () { + var $next = $get('next').focus(); + if ($next.size()) return; + + var list = $listGetter($scope); + var next = parse(parse(_.last(list)) + 1); + if (next === INVALID) return; + + list.push(next); + }, + 'shift-enter': function () { + $get('prev').focus(); + }, - var nums = _(viewValue.split(',')) - .invoke('trim') - .filter(Boolean) - .map(function (num) { - // prevent '100 boats' from passing - return FLOATABLE.test(num) ? parseFloat(num) : NaN; - }); + 'delete': function (event) { + if ($el.val() === '') { + $get('prev').focus(); + var list = $listGetter($scope); + list.splice($scope.$index, 1); + event.preventDefault(); + } - var ration = nums.none(_.isNaN); - var ord = ration && nums.isOrdinal(); - var range = ord && nums.min() >= 0 && nums.max() <= 100; + return false; + } + }; - return range ? nums.value() : INVALID; + function $get(dir) { + return $repeater[dir]().find('[percent-list]'); } - function makeString(list) { - if (!_.isArray(list)) return INVALID; - return list.join(', '); + function idKey(event) { + var id = []; + if (event.ctrlKey) id.push('ctrl'); + if (event.shiftKey) id.push('shift'); + if (event.metaKey) id.push('meta'); + if (event.altKey) id.push('alt'); + id.push(namedKeys[event.keyCode] || event.keyCode); + return id.join('-'); + } + + function add(n, val) { + return parse(val + n); + } + + function addTenth(n, val, str) { + var int = Math.floor(val); + var dec = parseInt(str.split('.')[1] || 0, 10); + dec = dec + parseInt(n, 10); + + if (dec < 0 || dec > 9) { + int += Math.floor(dec / 10); + dec = dec % 10; + } + + return parse(int + '.' + dec); } - function converter(/* fns... */) { - var fns = _.toArray(arguments); - return function (input) { - var value = input; - var valid = fns.every(function (fn) { - return (value = fn(value)) !== INVALID; - }); + function change(using, mod) { + return function () { + var str = String(ngModelController.$viewValue); + var val = parse(str); + if (val === INVALID) return; - ngModelCntr.$setValidity('listInput', valid); - return valid ? value : void 0; + var next = using(mod, val, str); + if (next === INVALID) return; + + $el.val(next); + ngModelController.$setViewValue(next); }; } - ngModelCntr.$parsers.push(converter(parse)); - ngModelCntr.$formatters.push(converter(makeString)); + function onKeydown(event) { + var handler = handlers[idKey(event)]; + if (!handler) return; + + if (handler(event) !== false) { + event.preventDefault(); + } + + $scope.$apply(); + } + + $el.on('keydown', onKeydown); + $scope.$on('$destroy', function () { + $el.off('keydown', onKeydown); + }); + + function parse(viewValue) { + viewValue = String(viewValue || 0); + var num = viewValue.trim(); + if (!FLOATABLE.test(num)) return INVALID; + num = parseFloat(num); + if (isNaN(num)) return INVALID; + + var list = $listGetter($scope); + var min = list[$scope.$index - 1] || 0; + var max = list[$scope.$index + 1] || 100; + + if (num <= min || num >= max) return INVALID; + + return num; + } + + $scope.$watchMulti([ + '$index', + { + fn: $scope.$watchCollection, + get: function () { + return $listGetter($scope); + } + } + ], function () { + var valid = parse(ngModelController.$viewValue) !== INVALID; + ngModelController.$setValidity('percentList', valid); + }); + + ngModelController.$parsers.push(function (viewValue) { + var value = parse(viewValue); + var valid = value !== INVALID; + ngModelController.$setValidity('percentList', valid); + return valid ? value : void 0; + }); } }; }); diff --git a/src/kibana/components/agg_types/controls/percents.html b/src/kibana/components/agg_types/controls/percents.html index eba912dfc2fb07..0f6039847e6988 100644 --- a/src/kibana/components/agg_types/controls/percents.html +++ b/src/kibana/components/agg_types/controls/percents.html @@ -1,8 +1,24 @@
- -
\ No newline at end of file + +
+ + + + +
+
+ + \ No newline at end of file From ccdbab11914777db303401e52431a6eddd5e4d15 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 16:52:04 -0700 Subject: [PATCH 105/142] Replace duplicate phrase query building stuff --- .../filter_manager/filter_manager.js | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/kibana/components/filter_manager/filter_manager.js b/src/kibana/components/filter_manager/filter_manager.js index ede139c03116fc..dfd71b3b0783e3 100644 --- a/src/kibana/components/filter_manager/filter_manager.js +++ b/src/kibana/components/filter_manager/filter_manager.js @@ -1,6 +1,8 @@ // Adds a filter to a passed state define(function (require) { var _ = require('lodash'); + var buildPhraseQuery = require('components/filter_manager/lib/phrase'); + var self = this; this.init = function ($state) { @@ -44,23 +46,9 @@ define(function (require) { filters.push({ meta: { negate: negate, index: index }, exists: { field: value } }); break; default: - var filter; - if (field.scripted) { - filter = { - meta: { negate: negate, index: index, field: fieldName }, - script: { - script: '(' + field.script + ') == value', - params: { - value: value - } - } - }; - } else { - filter = { meta: { negate: negate, index: index }, query: { match: {} } }; - filter.query.match[fieldName] = { query: value, type: 'phrase' }; - } + var filter = buildPhraseQuery(field, value); + filter.meta.negate = negate; filters.push(filter); - break; } }); From f411bf78671d8e4b95bea8d78f0304e687c18da1 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Thu, 8 Jan 2015 21:38:27 -0700 Subject: [PATCH 106/142] Fix text, pass indexPattern directly --- .../buckets/create_filter/date_histogram.js | 2 +- .../buckets/create_filter/filters.js | 4 ++-- .../buckets/create_filter/histogram.js | 2 +- .../agg_types/buckets/create_filter/range.js | 2 +- .../agg_types/buckets/create_filter/terms.js | 4 ++-- .../filter_manager/filter_manager.js | 20 +++++++++++++++---- .../components/filter_manager/lib/phrase.js | 4 ++-- .../components/filter_manager/lib/query.js | 2 +- .../components/filter_manager/lib/range.js | 5 +++-- .../index_patterns/_index_pattern.js | 3 --- 10 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js b/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js index 285ec321680f4c..f2b7f4ec89fd2d 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js +++ b/src/kibana/components/agg_types/buckets/create_filter/date_histogram.js @@ -12,7 +12,7 @@ define(function (require) { return buildRangeFilter(aggConfig.params.field, { gte: parseInt(key, 10), lte: date.valueOf() - }); + }, aggConfig.vis.indexPattern); }; }; diff --git a/src/kibana/components/agg_types/buckets/create_filter/filters.js b/src/kibana/components/agg_types/buckets/create_filter/filters.js index ba263ec61dda79..00a5aca5854933 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/filters.js +++ b/src/kibana/components/agg_types/buckets/create_filter/filters.js @@ -1,5 +1,5 @@ define(function (require) { - var buildFilterQuery = require('components/filter_manager/lib/query'); + var buildQueryFilter = require('components/filter_manager/lib/query'); var _ = require('lodash'); return function CreateFilterFiltersProvider(Private) { return function (aggConfig, key) { @@ -8,7 +8,7 @@ define(function (require) { var filter = dslFilters[key]; if (filter) { - return buildFilterQuery(filter.query, aggConfig.vis.indexPattern.id); + return buildQueryFilter(filter.query, aggConfig.vis.indexPattern.id); } }; }; diff --git a/src/kibana/components/agg_types/buckets/create_filter/histogram.js b/src/kibana/components/agg_types/buckets/create_filter/histogram.js index b0c7d9ea380d89..302fec17e07098 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/histogram.js +++ b/src/kibana/components/agg_types/buckets/create_filter/histogram.js @@ -8,7 +8,7 @@ define(function (require) { return buildRangeFilter(aggConfig.params.field, { gte: value, lt: value + aggConfig.params.interval - }); + }, aggConfig.vis.indexPattern); }; }; }); diff --git a/src/kibana/components/agg_types/buckets/create_filter/range.js b/src/kibana/components/agg_types/buckets/create_filter/range.js index 845e561acea0d3..ee230d7028f281 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/range.js +++ b/src/kibana/components/agg_types/buckets/create_filter/range.js @@ -8,7 +8,7 @@ define(function (require) { return buildRangeFilter(aggConfig.params.field, { gte: gte, lte: lte - }); + }, aggConfig.vis.indexPattern); }; }; }); diff --git a/src/kibana/components/agg_types/buckets/create_filter/terms.js b/src/kibana/components/agg_types/buckets/create_filter/terms.js index ba81fb02ae1315..0745be5b828905 100644 --- a/src/kibana/components/agg_types/buckets/create_filter/terms.js +++ b/src/kibana/components/agg_types/buckets/create_filter/terms.js @@ -1,8 +1,8 @@ define(function (require) { - var buildPhraseQuery = require('components/filter_manager/lib/phrase'); + var buildPhraseFilter = require('components/filter_manager/lib/phrase'); return function createTermsFilterProvider(Private) { return function (aggConfig, key) { - return buildPhraseQuery(aggConfig.params.field, key); + return buildPhraseFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern); }; }; }); diff --git a/src/kibana/components/filter_manager/filter_manager.js b/src/kibana/components/filter_manager/filter_manager.js index dfd71b3b0783e3..ede139c03116fc 100644 --- a/src/kibana/components/filter_manager/filter_manager.js +++ b/src/kibana/components/filter_manager/filter_manager.js @@ -1,8 +1,6 @@ // Adds a filter to a passed state define(function (require) { var _ = require('lodash'); - var buildPhraseQuery = require('components/filter_manager/lib/phrase'); - var self = this; this.init = function ($state) { @@ -46,9 +44,23 @@ define(function (require) { filters.push({ meta: { negate: negate, index: index }, exists: { field: value } }); break; default: - var filter = buildPhraseQuery(field, value); - filter.meta.negate = negate; + var filter; + if (field.scripted) { + filter = { + meta: { negate: negate, index: index, field: fieldName }, + script: { + script: '(' + field.script + ') == value', + params: { + value: value + } + } + }; + } else { + filter = { meta: { negate: negate, index: index }, query: { match: {} } }; + filter.query.match[fieldName] = { query: value, type: 'phrase' }; + } filters.push(filter); + break; } }); diff --git a/src/kibana/components/filter_manager/lib/phrase.js b/src/kibana/components/filter_manager/lib/phrase.js index e78c93b84c6e67..41d042c3aa332f 100644 --- a/src/kibana/components/filter_manager/lib/phrase.js +++ b/src/kibana/components/filter_manager/lib/phrase.js @@ -1,7 +1,7 @@ define(function (require) { var _ = require('lodash'); - return function buildPhraseFilter(field, value) { - var filter = { meta: { index: field.indexPattern.id} }; + return function buildPhraseFilter(field, value, indexPattern) { + var filter = { meta: { index: indexPattern.id} }; if (field.scripted) { filter.script = { diff --git a/src/kibana/components/filter_manager/lib/query.js b/src/kibana/components/filter_manager/lib/query.js index 9d4d53df544135..fff4fd869b6cd1 100644 --- a/src/kibana/components/filter_manager/lib/query.js +++ b/src/kibana/components/filter_manager/lib/query.js @@ -1,6 +1,6 @@ define(function (require) { var _ = require('lodash'); - return function buildPhraseFilter(query, index) { + return function buildQueryFilter(query, index) { return { query: query, meta: { diff --git a/src/kibana/components/filter_manager/lib/range.js b/src/kibana/components/filter_manager/lib/range.js index cbf0cb0f862e06..2a05c7d20ea39a 100644 --- a/src/kibana/components/filter_manager/lib/range.js +++ b/src/kibana/components/filter_manager/lib/range.js @@ -1,7 +1,7 @@ define(function (require) { var _ = require('lodash'); - return function buildRangeFilter(field, params) { - var filter = { meta: { index: field.indexPattern.id} }; + return function buildRangeFilter(field, params, indexPattern) { + var filter = { meta: { index: indexPattern.id} }; if (params.gte && params.gt) throw new Error('gte and gt are mutually exclusive'); if (params.lte && params.lt) throw new Error('lte and lt are mutually exclusive'); @@ -26,6 +26,7 @@ define(function (require) { filter.script.params.value = value; filter.meta.field = field.name; } else { + filter.range = {}; filter.range[field.name] = params; } return filter; diff --git a/src/kibana/components/index_patterns/_index_pattern.js b/src/kibana/components/index_patterns/_index_pattern.js index 5f725bdd7dc03a..d98f53aa6e82db 100644 --- a/src/kibana/components/index_patterns/_index_pattern.js +++ b/src/kibana/components/index_patterns/_index_pattern.js @@ -112,9 +112,6 @@ define(function (require) { return formatName ? fieldFormats.byName[formatName] : fieldFormats.defaultByType[field.type]; } }, - indexPattern: { - value: self - }, sortable: { value: field.indexed && type.sortable }, From 1610b36a2035fd32b91106a046e6483bc0c33c39 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 08:15:55 -0700 Subject: [PATCH 107/142] Format field when using range filters --- src/kibana/components/filter_manager/lib/range.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kibana/components/filter_manager/lib/range.js b/src/kibana/components/filter_manager/lib/range.js index 2a05c7d20ea39a..232ff63de56cbf 100644 --- a/src/kibana/components/filter_manager/lib/range.js +++ b/src/kibana/components/filter_manager/lib/range.js @@ -14,12 +14,12 @@ define(function (require) { lt: '<', }; - var script = _.map(params, function (value, key) { + var script = _.map(params, function (val, key) { return '(' + field.script + ')' + operators[key] + key; }).join(' && '); - var value = _.map(params, function (value, key) { - return '+' + operators[key] + value; + var value = _.map(params, function (val, key) { + return '+' + operators[key] + field.format.convert(val); }).join(' '); filter.script = { script: script, params: params }; From bd81331af06bbab0ad479083e44a1003f6df4178 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 08:16:55 -0700 Subject: [PATCH 108/142] Also check if the field is a string, closes #2578 --- .../plugins/discover/components/field_chooser/discover_field.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/plugins/discover/components/field_chooser/discover_field.js b/src/kibana/plugins/discover/components/field_chooser/discover_field.js index 78d7ffa8418f5c..159c3d579f6acc 100644 --- a/src/kibana/plugins/discover/components/field_chooser/discover_field.js +++ b/src/kibana/plugins/discover/components/field_chooser/discover_field.js @@ -32,7 +32,7 @@ define(function (require) { warnings.push('Doc values are not enabled on this field. This may lead to excess heap consumption when visualizing.'); } - if (field.analyzed) { + if (field.analyzed && field.type === 'string') { warnings.push('This is an analyzed string field.' + ' Analyzed strings are highly unique and can use a lot of memory to visualize.'); } From e701d699aa42a4d676bfaf4974b14e2a62e1bd38 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 08:21:38 -0700 Subject: [PATCH 109/142] remove + --- src/kibana/components/filter_manager/lib/range.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/filter_manager/lib/range.js b/src/kibana/components/filter_manager/lib/range.js index 232ff63de56cbf..fba79cdb9cc3e4 100644 --- a/src/kibana/components/filter_manager/lib/range.js +++ b/src/kibana/components/filter_manager/lib/range.js @@ -19,7 +19,7 @@ define(function (require) { }).join(' && '); var value = _.map(params, function (val, key) { - return '+' + operators[key] + field.format.convert(val); + return operators[key] + field.format.convert(val); }).join(' '); filter.script = { script: script, params: params }; From 57cbea73a34416526c399838cda05ac7638fa933 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 09:40:10 -0700 Subject: [PATCH 110/142] Add tests for filter builders --- test/unit/fixtures/filter_skeleton.js | 7 ++ test/unit/fixtures/logstash_fields.js | 4 +- .../stubbed_logstash_index_pattern.js | 1 + .../specs/components/filter_bar/mapScript.js | 6 +- .../components/filter_manager/lib/phrase.js | 43 ++++++++++++ .../components/filter_manager/lib/query.js | 28 ++++++++ .../components/filter_manager/lib/range.js | 66 +++++++++++++++++++ 7 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 test/unit/fixtures/filter_skeleton.js create mode 100644 test/unit/specs/components/filter_manager/lib/phrase.js create mode 100644 test/unit/specs/components/filter_manager/lib/query.js create mode 100644 test/unit/specs/components/filter_manager/lib/range.js diff --git a/test/unit/fixtures/filter_skeleton.js b/test/unit/fixtures/filter_skeleton.js new file mode 100644 index 00000000000000..f1eb523d428d28 --- /dev/null +++ b/test/unit/fixtures/filter_skeleton.js @@ -0,0 +1,7 @@ +define(function (require) { + return { + meta: { + index: 'logstash-*' + } + }; +}); diff --git a/test/unit/fixtures/logstash_fields.js b/test/unit/fixtures/logstash_fields.js index 67d005d5d0bea1..3ebf19d8f118e2 100644 --- a/test/unit/fixtures/logstash_fields.js +++ b/test/unit/fixtures/logstash_fields.js @@ -16,8 +16,8 @@ define(function (require) { { name: 'geo.src', type: 'string', indexed: true, analyzed: true }, { name: '_type', type: 'string', indexed: true, analyzed: true }, { name: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false }, - { name: 'scritped string', type: 'string', scripted: true, script: '\'i am a string\''}, - { name: 'scritped number', type: 'number', scripted: true, script: '1234'}, + { name: 'script string', type: 'string', scripted: true, script: '\'i am a string\''}, + { name: 'script number', type: 'number', scripted: true, script: '1234'}, ].map(function (field) { field.count = field.count || 0; field.scripted = field.scripted || false; diff --git a/test/unit/fixtures/stubbed_logstash_index_pattern.js b/test/unit/fixtures/stubbed_logstash_index_pattern.js index 834a0a312c5ed7..b5669f0ea43a4e 100644 --- a/test/unit/fixtures/stubbed_logstash_index_pattern.js +++ b/test/unit/fixtures/stubbed_logstash_index_pattern.js @@ -24,6 +24,7 @@ define(function (require) { indexPattern.flattenSearchResponse = _.bind(flattenSearchResponse, indexPattern); indexPattern.flattenHit = _.bind(flattenHit, indexPattern); indexPattern.metaFields = ['_id', '_type', '_source']; + indexPattern.id = 'logstash-*'; return indexPattern; diff --git a/test/unit/specs/components/filter_bar/mapScript.js b/test/unit/specs/components/filter_bar/mapScript.js index d44aaade1f6bd1..c43f023f5aff54 100644 --- a/test/unit/specs/components/filter_bar/mapScript.js +++ b/test/unit/specs/components/filter_bar/mapScript.js @@ -25,11 +25,11 @@ define(function (require) { it('should return the key and value for matching filters', function (done) { var filter = { - meta: { index: 'logstash-*', field: 'scritped number' }, - script: { script: 'doc["scritped number"].value * 5', params: { value: 35}} + meta: { index: 'logstash-*', field: 'script number' }, + script: { script: 'doc["script number"].value * 5', params: { value: 35}} }; mapScript(filter).then(function (result) { - expect(result).to.have.property('key', 'scritped number'); + expect(result).to.have.property('key', 'script number'); expect(result).to.have.property('value', 35); done(); }); diff --git a/test/unit/specs/components/filter_manager/lib/phrase.js b/test/unit/specs/components/filter_manager/lib/phrase.js new file mode 100644 index 00000000000000..399771ab37e223 --- /dev/null +++ b/test/unit/specs/components/filter_manager/lib/phrase.js @@ -0,0 +1,43 @@ +/* global sinon */ +define(function (require) { + var fn = require('components/filter_manager/lib/phrase'); + var _ = require('lodash'); + var indexPattern, expected; + describe('Filter Manager', function () { + describe('Phrase filter builder', function () { + beforeEach(module('kibana')); + beforeEach(inject(function (Private, _$rootScope_, Promise) { + indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); + expected = _.cloneDeep(require('fixtures/filter_skeleton')); + })); + + it('should be a function', function () { + expect(fn).to.be.a(Function); + }); + + it('should return a match query filter when passed a standard field', function () { + expected.query = { + match: { + bytes: { + query: 5, + type: 'phrase' + } + } + }; + expect(fn(indexPattern.fields.byName.bytes, 5, indexPattern)).to.eql(expected); + }); + + it('should return a script filter when passed a scripted field', function () { + expected.meta.field = 'script number'; + expected.script = { + script: '(' + indexPattern.fields.byName['script number'].script + ') == value', + params: { + value: 5, + } + }; + expect(fn(indexPattern.fields.byName['script number'], 5, indexPattern)).to.eql(expected); + }); + }); + }); +}); + diff --git a/test/unit/specs/components/filter_manager/lib/query.js b/test/unit/specs/components/filter_manager/lib/query.js new file mode 100644 index 00000000000000..41ebdf72abc72f --- /dev/null +++ b/test/unit/specs/components/filter_manager/lib/query.js @@ -0,0 +1,28 @@ +/* global sinon */ +define(function (require) { + var fn = require('components/filter_manager/lib/query'); + var _ = require('lodash'); + var indexPattern, expected; + describe('Filter Manager', function () { + describe('Phrase filter builder', function () { + beforeEach(module('kibana')); + beforeEach(inject(function (Private, _$rootScope_, Promise) { + indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); + expected = _.cloneDeep(require('fixtures/filter_skeleton')); + })); + + it('should be a function', function () { + expect(fn).to.be.a(Function); + }); + + it('should return a query filter when passed a standard field', function () { + expected.query = { + foo: 'bar' + }; + expect(fn({foo: 'bar'}, indexPattern.id)).to.eql(expected); + }); + + }); + }); +}); + diff --git a/test/unit/specs/components/filter_manager/lib/range.js b/test/unit/specs/components/filter_manager/lib/range.js new file mode 100644 index 00000000000000..80a971389b337c --- /dev/null +++ b/test/unit/specs/components/filter_manager/lib/range.js @@ -0,0 +1,66 @@ +/* global sinon */ +define(function (require) { + var fn = require('components/filter_manager/lib/range'); + var _ = require('lodash'); + var indexPattern, expected; + describe('Filter Manager', function () { + describe('Range filter builder', function () { + beforeEach(module('kibana')); + beforeEach(inject(function (Private, _$rootScope_, Promise) { + indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); + expected = _.cloneDeep(require('fixtures/filter_skeleton')); + })); + + it('should be a function', function () { + expect(fn).to.be.a(Function); + }); + + it('should return a range filter when passed a standard field', function () { + expected.range = { + bytes: { + gte: 1, + lte: 3 + } + }; + expect(fn(indexPattern.fields.byName.bytes, {gte: 1, lte: 3}, indexPattern)).to.eql(expected); + }); + + it('should return a script filter when passed a scripted field', function () { + expected.meta.field = 'script number'; + expected.script = { + script: '(' + indexPattern.fields.byName['script number'].script + ')>=gte && (' + + indexPattern.fields.byName['script number'].script + ')<=lte', + params: { + value: '>=1 <=3', + gte: 1, + lte: 3 + } + }; + expect(fn(indexPattern.fields.byName['script number'], {gte: 1, lte: 3}, indexPattern)).to.eql(expected); + }); + + it('should throw an error when gte and gt, or lte and lt are both passed', function () { + expect(function () { + fn(indexPattern.fields.byName['script number'], {gte: 1, gt: 3}, indexPattern); + }).to.throwError(); + expect(function () { + fn(indexPattern.fields.byName['script number'], {lte: 1, lt: 3}, indexPattern); + }).to.throwError(); + }); + + it('to use the right operator for each of gte, gt, lt and lte', function () { + _.each({gte: '>=', gt: '>', lte: '<=', lt: '<'}, function (operator, key) { + var params = {}; + params[key] = 5; + var filter = fn(indexPattern.fields.byName['script number'], params, indexPattern); + + expect(filter.script.script).to.be('(' + indexPattern.fields.byName['script number'].script + ')' + operator + key); + expect(filter.script.params[key]).to.be(5); + expect(filter.script.params.value).to.be(operator + 5); + + }); + }); + }); + }); +}); + From 5a65e0d1d701d7caaf9f3707f730495dfe276235 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 09:53:54 -0700 Subject: [PATCH 111/142] [aggTypes/percentiles] tie in the add and remove buttons --- .../agg_types/controls/_percent_list.js | 27 +++++++++---------- .../agg_types/controls/percents.html | 25 ++++++++++------- .../agg_types/metrics/percentiles.js | 15 ++++++++++- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/kibana/components/agg_types/controls/_percent_list.js b/src/kibana/components/agg_types/controls/_percent_list.js index 61b52f056ea9ed..7e05602e6c4ae8 100644 --- a/src/kibana/components/agg_types/controls/_percent_list.js +++ b/src/kibana/components/agg_types/controls/_percent_list.js @@ -19,6 +19,7 @@ define(function (require) { 13: 'enter', 38: 'up', 40: 'down', + 9: 'tab', 8: 'delete', 46: 'delete' }; @@ -30,25 +31,13 @@ define(function (require) { 'down': change(add, -1), 'shift-down': change(addTenth, -1), - 'enter': function () { - var $next = $get('next').focus(); - if ($next.size()) return; - - var list = $listGetter($scope); - var next = parse(parse(_.last(list)) + 1); - if (next === INVALID) return; - - list.push(next); - }, - 'shift-enter': function () { - $get('prev').focus(); - }, + 'tab': go('next'), + 'shift-tab': go('prev'), 'delete': function (event) { if ($el.val() === '') { $get('prev').focus(); - var list = $listGetter($scope); - list.splice($scope.$index, 1); + $scope.remove($scope.$index); event.preventDefault(); } @@ -60,6 +49,14 @@ define(function (require) { return $repeater[dir]().find('[percent-list]'); } + function go(dir) { + return function () { + var $to = $get(dir); + if ($to.size()) $to.focus(); + else return false; + }; + } + function idKey(event) { var id = []; if (event.ctrlKey) id.push('ctrl'); diff --git a/src/kibana/components/agg_types/controls/percents.html b/src/kibana/components/agg_types/controls/percents.html index 0f6039847e6988..ecc470f4270041 100644 --- a/src/kibana/components/agg_types/controls/percents.html +++ b/src/kibana/components/agg_types/controls/percents.html @@ -1,5 +1,5 @@ -
- +
+
@@ -10,15 +10,20 @@ input-focus class="form-control"> -
-
- \ No newline at end of file + +

+ You mush specify at least one percentile +

+ + +
\ No newline at end of file diff --git a/src/kibana/components/agg_types/metrics/percentiles.js b/src/kibana/components/agg_types/metrics/percentiles.js index 263823b1cc471a..f5958e8728ae34 100644 --- a/src/kibana/components/agg_types/metrics/percentiles.js +++ b/src/kibana/components/agg_types/metrics/percentiles.js @@ -29,7 +29,20 @@ define(function (require) { { name: 'percents', editor: percentEditor, - default: [1, 5, 25, 50, 75, 95, 99] + default: [1, 5, 25, 50, 75, 95, 99], + controller: function ($scope) { + $scope.remove = function (index) { + $scope.agg.params.percents.splice(index, 1); + }; + + $scope.add = function () { + $scope.agg.params.percents.push(_.last($scope.agg.params.percents) + 1); + }; + + $scope.$watchCollection('agg.params.percents', function (percents) { + $scope.validLength = _.size(percents) || null; + }); + } } ], getResponseAggs: function (agg) { From 270c06bc23a65998dc96561a1ea24c86ccb31481 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 09:55:05 -0700 Subject: [PATCH 112/142] Fix unrelated test --- test/unit/specs/apps/discover/directives/field_chooser.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/specs/apps/discover/directives/field_chooser.js b/test/unit/specs/apps/discover/directives/field_chooser.js index eaff7bd87d1fb4..e2b4d3bd00c7da 100644 --- a/test/unit/specs/apps/discover/directives/field_chooser.js +++ b/test/unit/specs/apps/discover/directives/field_chooser.js @@ -86,7 +86,7 @@ define(function (require) { expect(section.popular.text()).to.contain('ssl'); expect(section.popular.text()).to.contain('@timestamp'); - expect(section.popular.text()).to.not.contain('ip'); + expect(section.popular.text()).to.not.contain('ip\n'); expect(section.unpopular.text()).to.contain('extension'); expect(section.unpopular.text()).to.contain('area'); @@ -133,8 +133,8 @@ define(function (require) { indexPattern.fields.byName.ip.display = true; $scope.$digest(); - expect(section.selected.text()).to.contain('ip'); - expect(section.unpopular.text()).to.not.contain('ip'); + expect(section.selected.text()).to.contain('ip\n'); + expect(section.unpopular.text()).to.not.contain('ip\n'); expect(section.popular.text()).to.contain('ssl'); From c67f6d29548d9c178570376e2d79704d8b4b9fa9 Mon Sep 17 00:00:00 2001 From: Shelby Sturgis Date: Fri, 9 Jan 2015 12:28:11 -0500 Subject: [PATCH 113/142] refactoring area chart tests due to html dom elements being left over --- .../specs/vislib/visualizations/area_chart.js | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/test/unit/specs/vislib/visualizations/area_chart.js b/test/unit/specs/vislib/visualizations/area_chart.js index bb6c95bd4afe20..4c094df94994fb 100644 --- a/test/unit/specs/vislib/visualizations/area_chart.js +++ b/test/unit/specs/vislib/visualizations/area_chart.js @@ -57,44 +57,43 @@ define(function (require) { vis = null; }); - describe('checkIfEnoughData method', function () { - var errorVis; - var goodVis; + describe('checkIfEnoughData method throws an error when not enough data', function () { var notEnoughData; - var enoughData; beforeEach(function () { - inject(function (d3, Private) { - errorVis = Private(require('vislib_fixtures/_vis_fixture'))(visLibParams); - goodVis = Private(require('vislib_fixtures/_vis_fixture'))(visLibParams); - enoughData = require('vislib_fixtures/mock_data/date_histogram/_series'); + inject(function () { notEnoughData = require('vislib_fixtures/mock_data/not_enough_data/_one_point'); require('css!components/vislib/styles/main'); - errorVis.render(notEnoughData); - goodVis.render(enoughData); + vis.render(notEnoughData); }); }); - afterEach(function () { - $(errorVis.el).remove(); - $(goodVis.el).remove(); - errorVis = null; - goodVis = null; - }); - it('should throw a Not Enough Data Error', function () { var chart = { chartData: notEnoughData }; expect(function () { - errorVis.handler.ChartClass.prototype.checkIfEnoughData.apply(chart); + vis.handler.ChartClass.prototype.checkIfEnoughData.apply(chart); }).to.throwError(); }); + }); + + describe('checkIfEnoughData method should not throw an error when enough data', function () { + var enoughData; + + beforeEach(function () { + inject(function () { + enoughData = require('vislib_fixtures/mock_data/date_histogram/_series'); + require('css!components/vislib/styles/main'); + + vis.render(enoughData); + }); + }); it('should not throw a Not Enough Data Error', function () { - goodVis.handler.charts.forEach(function (chart) { + vis.handler.charts.forEach(function (chart) { expect(function () { chart.checkIfEnoughData(); }).to.not.throwError(); From c5c5449d0db4b382ff10473532f193e6ecefe84e Mon Sep 17 00:00:00 2001 From: lukasolson Date: Fri, 9 Jan 2015 10:54:05 -0700 Subject: [PATCH 114/142] Hide query bar on visualizations that don't require search --- src/kibana/plugins/visualize/editor/editor.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html index 4d933ed742185c..bd434545924038 100644 --- a/src/kibana/plugins/visualize/editor/editor.html +++ b/src/kibana/plugins/visualize/editor/editor.html @@ -2,7 +2,7 @@
-
@@ -12,11 +12,11 @@ {{ savedVis.savedSearchId | json}}
-
+
Unlinked!
-
+
-
+
From f6f883ceca635c7060d5718b10c7c001cce4996d Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 11:15:50 -0700 Subject: [PATCH 115/142] [aggTypes/percentile] move key map into util file --- .../agg_types/controls/_percent_list.js | 37 +++---- src/kibana/utils/key_map.js | 104 ++++++++++++++++++ 2 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 src/kibana/utils/key_map.js diff --git a/src/kibana/components/agg_types/controls/_percent_list.js b/src/kibana/components/agg_types/controls/_percent_list.js index 7e05602e6c4ae8..cc340602ad5e22 100644 --- a/src/kibana/components/agg_types/controls/_percent_list.js +++ b/src/kibana/components/agg_types/controls/_percent_list.js @@ -1,6 +1,7 @@ define(function (require) { var $ = require('jquery'); var _ = require('lodash'); + var keyMap = require('utils/key_map'); var INVALID = {}; // invalid flag var FLOATABLE = /^[\d\.e\-\+]+$/i; @@ -15,35 +16,29 @@ define(function (require) { var $repeater = $el.closest('[ng-repeat]'); var $listGetter = $parse(attrs.percentList); - var namedKeys = { - 13: 'enter', - 38: 'up', - 40: 'down', - 9: 'tab', - 8: 'delete', - 46: 'delete' - }; - var handlers = { - 'up': change(add, 1), + up: change(add, 1), 'shift-up': change(addTenth, 1), - 'down': change(add, -1), + down: change(add, -1), 'shift-down': change(addTenth, -1), - 'tab': go('next'), + tab: go('next'), 'shift-tab': go('prev'), - 'delete': function (event) { - if ($el.val() === '') { - $get('prev').focus(); - $scope.remove($scope.$index); - event.preventDefault(); - } + backspace: removeIfEmpty, + delete: removeIfEmpty + }; - return false; + function removeIfEmpty(event) { + if ($el.val() === '') { + $get('prev').focus(); + $scope.remove($scope.$index); + event.preventDefault(); } - }; + + return false; + } function $get(dir) { return $repeater[dir]().find('[percent-list]'); @@ -63,7 +58,7 @@ define(function (require) { if (event.shiftKey) id.push('shift'); if (event.metaKey) id.push('meta'); if (event.altKey) id.push('alt'); - id.push(namedKeys[event.keyCode] || event.keyCode); + id.push(keyMap[event.keyCode] || event.keyCode); return id.join('-'); } diff --git a/src/kibana/utils/key_map.js b/src/kibana/utils/key_map.js new file mode 100644 index 00000000000000..ee78dd1ba6c115 --- /dev/null +++ b/src/kibana/utils/key_map.js @@ -0,0 +1,104 @@ +define(function (require) { + return { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 19: 'pause', + 20: 'capsLock', + 27: 'escape', + 32: 'space', + 33: 'pageUp', + 34: 'pageDown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'insert', + 46: 'delete', + 48: '0', + 49: '1', + 50: '2', + 51: '3', + 52: '4', + 53: '5', + 54: '6', + 55: '7', + 56: '8', + 57: '9', + 65: 'a', + 66: 'b', + 67: 'c', + 68: 'd', + 69: 'e', + 70: 'f', + 71: 'g', + 72: 'h', + 73: 'i', + 74: 'j', + 75: 'k', + 76: 'l', + 77: 'm', + 78: 'n', + 79: 'o', + 80: 'p', + 81: 'q', + 82: 'r', + 83: 's', + 84: 't', + 85: 'u', + 86: 'v', + 87: 'w', + 88: 'x', + 89: 'y', + 90: 'z', + 91: 'leftWindowKey', + 92: 'rightWindowKey', + 93: 'selectKey', + 96: '0', + 97: '1', + 98: '2', + 99: '3', + 100: '4', + 101: '5', + 102: '6', + 103: '7', + 104: '8', + 105: '9', + 106: 'multiply', + 107: 'add', + 109: 'subtract', + 110: 'period', + 111: 'divide', + 112: 'f1', + 113: 'f2', + 114: 'f3', + 115: 'f4', + 116: 'f5', + 117: 'f6', + 118: 'f7', + 119: 'f8', + 120: 'f9', + 121: 'f10', + 122: 'f11', + 123: 'f12', + 144: 'numLock', + 145: 'scrollLock', + 186: 'semiColon', + 187: 'equalSign', + 188: 'comma', + 189: 'dash', + 190: 'period', + 191: 'forwardSlash', + 192: 'graveAccent', + 219: 'openBracket', + 220: 'backSlash', + 221: 'closeBraket', + 222: 'singleQuote', + 224: 'meta' + }; +}); \ No newline at end of file From f9ee0b2fd5d1b6cf9c39cfa7adf2889cdf6d462e Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 12:24:55 -0700 Subject: [PATCH 116/142] [aggTypes/percentile] updated tests --- .../agg_types/controls/_percent_list.js | 28 ++- .../agg_types/controls/percent_list.js | 188 +++++++++++++----- test/utils/simulate_keys.js | 105 ++++++++++ 3 files changed, 268 insertions(+), 53 deletions(-) create mode 100644 test/utils/simulate_keys.js diff --git a/src/kibana/components/agg_types/controls/_percent_list.js b/src/kibana/components/agg_types/controls/_percent_list.js index cc340602ad5e22..4bce09e7d99537 100644 --- a/src/kibana/components/agg_types/controls/_percent_list.js +++ b/src/kibana/components/agg_types/controls/_percent_list.js @@ -13,6 +13,7 @@ define(function (require) { restrict: 'A', require: 'ngModel', link: function ($scope, $el, attrs, ngModelController) { + var $setModel = $parse(attrs.ngModel).assign; var $repeater = $el.closest('[ng-repeat]'); var $listGetter = $parse(attrs.percentList); @@ -73,7 +74,11 @@ define(function (require) { if (dec < 0 || dec > 9) { int += Math.floor(dec / 10); - dec = dec % 10; + if (dec < 0) { + dec = 10 + (dec % 10); + } else { + dec = dec % 10; + } } return parse(int + '.' + dec); @@ -138,12 +143,21 @@ define(function (require) { ngModelController.$setValidity('percentList', valid); }); - ngModelController.$parsers.push(function (viewValue) { - var value = parse(viewValue); - var valid = value !== INVALID; - ngModelController.$setValidity('percentList', valid); - return valid ? value : void 0; - }); + function validate(then) { + return function (input) { + var value = parse(input); + var valid = value !== INVALID; + value = valid ? value : void 0; + ngModelController.$setValidity('percentList', valid); + then && then(input, value); + return value; + }; + } + + ngModelController.$parsers.push(validate()); + ngModelController.$formatters.push(validate(function (input, value) { + if (input !== value) $setModel($scope, value); + })); } }; }); diff --git a/test/unit/specs/components/agg_types/controls/percent_list.js b/test/unit/specs/components/agg_types/controls/percent_list.js index a9cbae4bc3f478..eaf82aab078ebb 100644 --- a/test/unit/specs/components/agg_types/controls/percent_list.js +++ b/test/unit/specs/components/agg_types/controls/percent_list.js @@ -2,21 +2,31 @@ define(function (require) { describe('PercentList directive', function () { var $ = require('jquery'); var _ = require('lodash'); + var simulateKeys = require('test_utils/simulate_keys'); require('components/agg_types/controls/_percent_list'); var $el; var $scope; - var $compile; - var $rootScope; + var compile; beforeEach(module('kibana')); beforeEach(inject(function ($injector) { - $rootScope = $injector.get('$rootScope'); - $compile = $injector.get('$compile'); + var $compile = $injector.get('$compile'); + var $rootScope = $injector.get('$rootScope'); - $el = $('').attr('ng-model', 'val').attr('percent-list', ''); $scope = $rootScope.$new(); + $el = $('
').append( + $('') + .attr('ng-model', 'vals[$index]') + .attr('ng-repeat', 'val in vals') + .attr('percent-list', 'vals') + ); + compile = function (vals) { + $scope.vals = vals || []; + $compile($el)($scope); + $scope.$apply(); + }; })); afterEach(function () { @@ -24,57 +34,143 @@ define(function (require) { $scope.$destroy(); }); - it('filters out empty entries', function () { - $compile($el)($scope); - - $el.val(',,1, ,, ,2, ,\n,'); - $el.change(); - expect($scope.val).to.eql([1, 2]); - }); - it('fails on invalid numbers', function () { - $compile($el)($scope); - - $el.val('foo,bar'); - $el.change(); - expect($scope.val).to.be(undefined); - expect($el.hasClass('ng-invalid')).to.be(true); + compile([1, 'foo']); + expect($scope.vals).to.eql([1, undefined]); + expect($el.find('.ng-invalid').size()).to.be(1); }); it('supports decimals', function () { - $compile($el)($scope); - - $el.val('1.2,000001.6,99.10'); - $el.change(); - expect($scope.val).to.eql([1.2, 1.6, 99.10]); + compile(['1.2', '000001.6', '99.10']); + expect($scope.vals).to.eql([1.2, 1.6, 99.1]); }); it('ensures that the values are in order', function () { - $compile($el)($scope); - - $el.val('1, 2, 3, 10, 4, 5'); - $el.change(); - expect($scope.val).to.be(undefined); - expect($el.hasClass('ng-invalid')).to.be(true); + compile([1, 2, 3, 10, 4, 5]); + expect($scope.vals).to.eql([1, 2, 3, undefined, 4, 5]); + expect($el.find('.ng-invalid').size()).to.be(1); }); - it('ensures that the values are less between 0 and 100', function () { - $compile($el)($scope); - - $el.val('-1, 0, 1'); - $el.change(); - expect($scope.val).to.be(undefined); - expect($el.hasClass('ng-invalid')).to.be(true); - - $el.val('0, 1'); - $el.change(); - expect($scope.val).to.eql([0, 1]); - expect($el.hasClass('ng-invalid')).to.be(false); + describe('ensures that the values are between 0 and 100', function () { + it(': -1', function () { + compile([-1, 1]); + expect($scope.vals).to.eql([undefined, 1]); + expect($el.find('.ng-invalid').size()).to.be(1); + }); + + it(': 0', function () { + compile([0, 1]); + expect($scope.vals).to.eql([undefined, 1]); + expect($el.find('.ng-invalid').size()).to.be(1); + }); + + it(': 0.0001', function () { + compile([0.0001, 1]); + expect($scope.vals).to.eql([0.0001, 1]); + expect($el.find('.ng-invalid').size()).to.be(0); + }); + + it(': 99.9999999', function () { + compile([1, 99.9999999]); + expect($scope.vals).to.eql([1, 99.9999999]); + expect($el.find('.ng-invalid').size()).to.be(0); + }); + + it(': 101', function () { + compile([1, 101]); + expect($scope.vals).to.eql([1, undefined]); + expect($el.find('.ng-invalid').size()).to.be(1); + }); + }); - $el.val('1, 101'); - $el.change(); - expect($scope.val).to.be(undefined); - expect($el.hasClass('ng-invalid')).to.be(true); + describe('listens for keyboard events', function () { + it('up arrow increases by 1', function () { + compile([1]); + + return simulateKeys( + function () { return $el.find('input').first(); }, + ['up', 'up', 'up'] + ) + .then(function () { + expect($scope.vals).to.eql([4]); + }); + }); + + it('shift-up increases by 0.1', function () { + compile([4.8]); + + var seq = [ + { + type: 'press', + key: 'shift', + events: [ + 'up', + 'up', + 'up' + ] + } + ]; + + return simulateKeys( + function () { return $el.find('input').first(); }, + seq + ) + .then(function () { + expect($scope.vals).to.eql([5.1]); + }); + }); + + it('down arrow decreases by 1', function () { + compile([5]); + + return simulateKeys( + function () { return $el.find('input').first(); }, + ['down', 'down', 'down'] + ) + .then(function () { + expect($scope.vals).to.eql([2]); + }); + }); + + it('shift-down decreases by 0.1', function () { + compile([5.1]); + + var seq = [ + { + type: 'press', + key: 'shift', + events: [ + 'down', + 'down', + 'down' + ] + } + ]; + + return simulateKeys( + function () { return $el.find('input').first(); }, + seq + ) + .then(function () { + expect($scope.vals).to.eql([4.8]); + }); + }); + + it('maintains valid number', function () { + compile([9, 11, 13]); + + var seq = [ + 'down', // 10 (11 - 1) + 'down' // 10 (limited by 9) + ]; + + var getEl = function () { return $el.find('input').eq(1); }; + + return simulateKeys(getEl, seq) + .then(function () { + expect($scope.vals).to.eql([9, 10, 13]); + }); + }); }); }); }); \ No newline at end of file diff --git a/test/utils/simulate_keys.js b/test/utils/simulate_keys.js new file mode 100644 index 00000000000000..53744e5f2cb191 --- /dev/null +++ b/test/utils/simulate_keys.js @@ -0,0 +1,105 @@ +define(function (require) { + var $ = require('jquery'); + var _ = require('lodash'); + var Promise = require('bluebird'); + var keyMap = require('utils/key_map'); + var reverseKeyMap = _.mapValues(_.invert(keyMap), _.limit(_.parseInt, 1)); + var KeyboardEvent = window.KeyboardEvent; + + /** + * Simulate keyboard events in an element. This allows testing the way that + * elements respond to keyboard input. + * + * # sequence style + * keyboard events occur in a sequence, this array of events describe that sequence. + * + * ## event + * an object with a type property, or a string which will be turned into a single press + * + * ## event types + * ### press + * represents a key press + * - `key`: the key for the button pressed + * - `events`: optional list of events that occur before this press completes + * + * ### wait + * represents a pause in a sequence + * - `ms`: the number of milliseconds that the pause takes + * + * ### repeat + * represents a key being repeated because it is held down. Should only exist as a + * sub event of `press` events. + * - `count`: the number of times the repeat occurs + * + * @param {element} $el - jQuery element where events should occur + * @param {[type]} sequence - an array of events + * @async + */ + return function ($el, sequence) { + var modifierState = { + ctrlKey: false, + shiftKey: false, + altKey: false, + metaKey: false + }; + + return doList(_.clone(sequence)); + + function setModifier(key, state) { + var name = key + 'Key'; + if (modifierState.hasOwnProperty(name)) { + modifierState[name] = !!state; + } + } + + function doList(list) { + return Promise.try(function () { + if (!list || !list.length) return; + + var event = list[0]; + if (_.isString(event)) { + event = { type: 'press', key: event }; + } + + switch (event.type) { + case 'press': + return Promise.resolve() + .then(_.partial(fire, 'keydown', event.key)) + .then(_.partial(fire, 'keypress', event.key)) + .then(_.partial(doList, event.events)) + .then(_.partial(fire, 'keyup', event.key)); + + case 'wait': + return Promise.delay(event.ms); + + case 'repeat': + return (function again(remaining) { + if (!remaining) return Promise.resolve(); + remaining = remaining - 1; + return Promise.resolve() + .then(_.partial(fire, 'keydown', event.key, true)) + .then(_.partial(fire, 'keypress', event.key, true)) + .then(_.partial(again, remaining)); + }(event.count)); + + default: + throw new TypeError('invalid event type "' + event.type + '"'); + } + }) + .then(function () { + if (_.size(list) > 1) return doList(list.slice(1)); + }); + } + + function fire(type, key, repeat) { + var keyCode = reverseKeyMap[key]; + if (!keyCode) throw new TypeError('invalid key "' + key + '"'); + + if (type === 'keydown') setModifier(key, true); + if (type === 'keyup') setModifier(key, false); + + var $target = _.isFunction($el) ? $el() : $el; + $target.trigger($.Event(type, _.defaults({ keyCode: keyCode }, modifierState))); + } + }; +}); \ No newline at end of file From 7cbc4746e7db4d4a62c73a3d0563eb918107d0f1 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 12:28:08 -0700 Subject: [PATCH 117/142] [aggConfigs] harden #getResponseAggById() --- src/kibana/components/vis/_agg_configs.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kibana/components/vis/_agg_configs.js b/src/kibana/components/vis/_agg_configs.js index a1069849a24c0f..51c4ae9e08b006 100644 --- a/src/kibana/components/vis/_agg_configs.js +++ b/src/kibana/components/vis/_agg_configs.js @@ -133,9 +133,11 @@ define(function (require) { * @return {AggConfig} */ AggConfigs.prototype.getResponseAggById = function (id) { + id = String(id); var reqAgg = _.find(this.getRequestAggs(), function (agg) { - return id.substr(0, agg.id.length) === agg.id; + return id.substr(0, String(agg.id).length) === agg.id; }); + if (!reqAgg) return; return _.find(reqAgg.getResponseAggs(), { id: id }); }; From f6567318a776b94e9f7b2fa4592d845a465f3a46 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 12:29:24 -0700 Subject: [PATCH 118/142] [$watchMulti] spelling error [ci skip] --- src/kibana/components/watch_multi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/watch_multi.js b/src/kibana/components/watch_multi.js index f0e5dbcb075c4f..1e1498b23cc554 100644 --- a/src/kibana/components/watch_multi.js +++ b/src/kibana/components/watch_multi.js @@ -36,7 +36,7 @@ define(function (require) { */ $delegate.constructor.prototype.$watchMulti = function (expressions, fn, deep) { if (!_.isArray(expressions)) throw new TypeError('expected an array of expressions to watch'); - if (!_.isFunction(fn)) throw new TypeError('expexted a function that is triggered on each watch'); + if (!_.isFunction(fn)) throw new TypeError('expected a function that is triggered on each watch'); var $scope = this; var fired = false; From af315c4238c8b2e203d46109da2f0cd6c191fea8 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 13:10:22 -0700 Subject: [PATCH 119/142] Ellipsis overflow for legends, show full text on hover. Closes #2237 --- src/kibana/components/vislib/lib/legend.js | 10 ++++- .../vislib/partials/legend_header.html | 11 +++-- .../components/vislib/styles/_legend.less | 43 +++++++++++-------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/kibana/components/vislib/lib/legend.js b/src/kibana/components/vislib/lib/legend.js index abdd7c6e835dd9..263a5637040f46 100644 --- a/src/kibana/components/vislib/lib/legend.js +++ b/src/kibana/components/vislib/lib/legend.js @@ -80,7 +80,7 @@ define(function (require) { return 'color ' + self.colorToClass(args.color(d)); }) .html(function (d) { - return '' + d; + return '' + d; }); }; @@ -136,6 +136,10 @@ define(function (require) { var liClass = '.' + self.colorToClass(self.color(d)); visEl.selectAll('.color').style('opacity', self._attr.blurredOpacity); + var eventEl = d3.select(this); + eventEl.style('white-space', 'inherit'); + eventEl.style('word-break', 'break-all'); + // select series on chart visEl.selectAll(liClass).style('opacity', self._attr.focusOpacity); }) @@ -148,6 +152,10 @@ define(function (require) { .selectAll('.color') .style('opacity', self._attr.defaultOpacity); + var eventEl = d3.select(this); + eventEl.style('white-space', 'nowrap'); + eventEl.style('word-break', 'inherit'); + // Legend values should always return to their default opacity of 1 visEl.select('.legend-ul') .selectAll('.color') diff --git a/src/kibana/components/vislib/partials/legend_header.html b/src/kibana/components/vislib/partials/legend_header.html index 86f384f2b17dea..58cec9eb2d3a57 100644 --- a/src/kibana/components/vislib/partials/legend_header.html +++ b/src/kibana/components/vislib/partials/legend_header.html @@ -1,3 +1,8 @@ - - - \ No newline at end of file +
+ + <%= (isOpen) ? + 'legend ' : + '' + %> + +
\ No newline at end of file diff --git a/src/kibana/components/vislib/styles/_legend.less b/src/kibana/components/vislib/styles/_legend.less index 209462c2db4deb..bf3d416e536d92 100644 --- a/src/kibana/components/vislib/styles/_legend.less +++ b/src/kibana/components/vislib/styles/_legend.less @@ -5,29 +5,40 @@ z-index: 10; overflow-x: hidden; overflow-y: auto; - min-width: 40px; min-height: 0; - .header { - width: 100%; - height: 26px; - margin: 0 0 14px 0; - visibility: visible; + .legend-toggle { + cursor: pointer; + opacity: 0.75; + white-space: nowrap; + font-size: 0.9em; + + .legend-open { + margin-right: 20px; + } + + .legend-closed { + font-size: 1.5em; + padding: 0 5px; + } + } + + .column-labels { + text-align: right; } .legend-ul { list-style-type: none; - margin: 0 0 0 14px; padding: 0; visibility: visible; .display(flex); .flex-direction(column); min-height: 0; - min-width: 0; + min-width: 60px; + margin-right: 5px; li.color { min-height: 22px; - margin: 0 18px 0 18px; padding: 3px 0 3px 0; text-align: left; font-size: 12px; @@ -36,15 +47,13 @@ cursor: default; text-align: left; .flex-grow(2); - word-wrap: break-word; + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; max-width: 150px; .dots { - width: 10px; - height: 10px; - border-radius: 50%; - float: left; - margin: 1px 0 0 -14px; + padding-right: 5px; } } } @@ -54,9 +63,5 @@ } .legend-toggle { - position: relative; - float: right; - right: 9px; - top: 9px; } } From ee82f9fe25dfa349ef8f91a87dc17eb2321b81d4 Mon Sep 17 00:00:00 2001 From: Rashid Khan Date: Fri, 9 Jan 2015 13:13:56 -0700 Subject: [PATCH 120/142] Uppercase legend --- src/kibana/components/vislib/partials/legend_header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/vislib/partials/legend_header.html b/src/kibana/components/vislib/partials/legend_header.html index 58cec9eb2d3a57..7c909bcee9920e 100644 --- a/src/kibana/components/vislib/partials/legend_header.html +++ b/src/kibana/components/vislib/partials/legend_header.html @@ -1,7 +1,7 @@
<%= (isOpen) ? - 'legend ' : + 'Legend ' : '' %> From 5af794c1cdddfea5e1a0c64db1b64f8f747764a0 Mon Sep 17 00:00:00 2001 From: lukasolson Date: Fri, 9 Jan 2015 13:41:53 -0700 Subject: [PATCH 121/142] Fix issue with scaled date histogram values (2510) --- src/kibana/components/agg_response/point_series/_get_point.js | 3 ++- .../agg_response/point_series/_tooltip_formatter.js | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/kibana/components/agg_response/point_series/_get_point.js b/src/kibana/components/agg_response/point_series/_get_point.js index 5756c40deaa932..fe63ab4daa8212 100644 --- a/src/kibana/components/agg_response/point_series/_get_point.js +++ b/src/kibana/components/agg_response/point_series/_get_point.js @@ -8,7 +8,8 @@ define(function (require) { var point = { x: unwrap(row[x.i], '_all'), y: unwrap(row[y.i]), - aggConfigResult: row[y.i] + aggConfigResult: row[y.i], + yScale: yScale }; if (series) { diff --git a/src/kibana/components/agg_response/point_series/_tooltip_formatter.js b/src/kibana/components/agg_response/point_series/_tooltip_formatter.js index 5b98c6871707b1..b90569969003c8 100644 --- a/src/kibana/components/agg_response/point_series/_tooltip_formatter.js +++ b/src/kibana/components/agg_response/point_series/_tooltip_formatter.js @@ -15,9 +15,11 @@ define(function (require) { var result = { $parent: datum.aggConfigResult }; while ((result = result.$parent) && result.aggConfig) { var agg = result.aggConfig; + var value = result.value; + if (agg === datum.aggConfigResult.aggConfig && datum.yScale != null) value *= datum.yScale; details.push({ - value: agg.fieldFormatter()(result.value), + value: agg.fieldFormatter()(value), label: agg.makeLabel() }); } From 8655a1826e3af88cd2fa2b1f668af9bffb25b03a Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 14:44:58 -0700 Subject: [PATCH 122/142] [aggConfig] #getResponseAggs() should always return an array --- src/kibana/components/vis/_agg_config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index 2ba030e5b591ca..2c0539349697dc 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -191,7 +191,7 @@ define(function (require) { AggConfig.prototype.getResponseAggs = function () { if (!this.type) return; - return this.type.getResponseAggs(this) || this; + return this.type.getResponseAggs(this) || [this]; }; AggConfig.prototype.getValue = function (bucket) { From 83bf3f6a3bdebb5c5e1ba0b08847176e986c45df Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 14:48:45 -0700 Subject: [PATCH 123/142] [kibana] don't set last path when embedded. Closes #2475 --- src/kibana/plugins/kibana/_apps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kibana/plugins/kibana/_apps.js b/src/kibana/plugins/kibana/_apps.js index b2ab9c425bbe39..003ad5b3862651 100644 --- a/src/kibana/plugins/kibana/_apps.js +++ b/src/kibana/plugins/kibana/_apps.js @@ -30,7 +30,7 @@ define(function (require) { var route = $location.path().split(/\//); var app = $rootScope.activeApp = _.find($scope.apps, { id: route[1] }); - if (!app) return; + if (!app || $scope.appEmbedded) return; // Record the last URL w/ state of the app, use for tab. setLastPath(app, globalState.removeFromUrl($location.url())); From e50d6ed73f4acdb29abf747cfeca14cd60e21282 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 15:03:16 -0700 Subject: [PATCH 124/142] [discover] close the save dialog when saving --- .../plugins/discover/controllers/discover.js | 40 +++++-------------- src/kibana/plugins/discover/index.html | 6 +-- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/kibana/plugins/discover/controllers/discover.js b/src/kibana/plugins/discover/controllers/discover.js index ca3632cc5a2641..0570e61a2e6cd7 100644 --- a/src/kibana/plugins/discover/controllers/discover.js +++ b/src/kibana/plugins/discover/controllers/discover.js @@ -2,9 +2,7 @@ define(function (require) { var _ = require('lodash'); var angular = require('angular'); var moment = require('moment'); - var settingsHtml = require('text!plugins/discover/partials/settings.html'); - var saveHtml = require('text!plugins/discover/partials/save_search.html'); - var loadHtml = require('text!plugins/discover/partials/load_search.html'); + var ConfigTemplate = require('utils/config_template'); var onlyDisabled = require('components/filter_bar/lib/onlyDisabled'); var filterManager = require('components/filter_manager/filter_manager'); @@ -60,6 +58,13 @@ define(function (require) { location: 'Discover' }); + // config panel templates + $scope.configTemplate = new ConfigTemplate({ + config: require('text!plugins/discover/partials/settings.html'), + load: require('text!plugins/discover/partials/load_search.html'), + save: require('text!plugins/discover/partials/save_search.html') + }); + $scope.timefilter = timefilter; // the saved savedSearch @@ -247,6 +252,8 @@ define(function (require) { return savedSearch.save() .then(function (id) { + $scope.configTemplate.close('save'); + if (id) { notify.info('Saved Data Source "' + savedSearch.title + '"'); if (savedSearch.id !== $route.current.params.id) { @@ -403,33 +410,6 @@ define(function (require) { }; }; - $scope.toggleConfig = function () { - // Close if already open - if ($scope.configTemplate === settingsHtml) { - delete $scope.configTemplate; - } else { - $scope.configTemplate = settingsHtml; - } - }; - - $scope.toggleSave = function () { - // Close if already open - if ($scope.configTemplate === saveHtml) { - delete $scope.configTemplate; - } else { - $scope.configTemplate = saveHtml; - } - }; - - $scope.toggleLoad = function () { - // Close if already open - if ($scope.configTemplate === loadHtml) { - delete $scope.configTemplate; - } else { - $scope.configTemplate = loadHtml; - } - }; - $scope.resetQuery = function () { $state.reset(); $scope.fetch(); diff --git a/src/kibana/plugins/discover/index.html b/src/kibana/plugins/discover/index.html index 7b0bf9a7d07ad3..bf91e7fbe729ac 100644 --- a/src/kibana/plugins/discover/index.html +++ b/src/kibana/plugins/discover/index.html @@ -25,13 +25,13 @@ - + - + - +
From ce59332b65d708e058544dc68fa70fa526339163 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 15:12:20 -0700 Subject: [PATCH 125/142] [dashboard] close the save dialog when saving --- src/kibana/plugins/dashboard/index.html | 10 +++++----- src/kibana/plugins/dashboard/index.js | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/kibana/plugins/dashboard/index.html b/src/kibana/plugins/dashboard/index.html index 56d173d341cb64..31edec20b6e647 100644 --- a/src/kibana/plugins/dashboard/index.html +++ b/src/kibana/plugins/dashboard/index.html @@ -32,16 +32,16 @@ - + - + - + - +
@@ -53,7 +53,7 @@

Ready to get started?

-

Click the button in the menu bar above to add a visualization to the dashboard.
If you haven't setup a visualization yet visit the "Visualize" tab to create your first visualization.

+

Click the button in the menu bar above to add a visualization to the dashboard.
If you haven't setup a visualization yet visit the "Visualize" tab to create your first visualization.

diff --git a/src/kibana/plugins/dashboard/index.js b/src/kibana/plugins/dashboard/index.js index 77eca8c3b29f83..7aa4e69ae9d224 100644 --- a/src/kibana/plugins/dashboard/index.js +++ b/src/kibana/plugins/dashboard/index.js @@ -82,10 +82,6 @@ define(function (require) { pickVis: require('text!plugins/dashboard/partials/pick_visualization.html') }); - $scope.openSave = _.partial($scope.configTemplate.toggle, 'save'); - $scope.openShare = _.partial($scope.configTemplate.toggle, 'share'); - $scope.openLoad = _.partial($scope.configTemplate.toggle, 'load'); - $scope.openAdd = _.partial($scope.configTemplate.toggle, 'pickVis'); $scope.refresh = _.bindKey(courier, 'fetch'); timefilter.enabled = true; @@ -141,6 +137,7 @@ define(function (require) { dash.save() .then(function (id) { + $scope.configTemplate.close('save'); if (id) { notify.info('Saved Dashboard as "' + dash.title + '"'); if (dash.id !== $routeParams.id) { From 31194f1dfbec734aa5aabae2dc117b8148956b09 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 15:14:49 -0700 Subject: [PATCH 126/142] [visualize/editor] close the save dialog when saving --- src/kibana/plugins/visualize/editor/editor.html | 6 +++--- src/kibana/plugins/visualize/editor/editor.js | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html index 243cac584a25be..8a2a141b5d2cde 100644 --- a/src/kibana/plugins/visualize/editor/editor.html +++ b/src/kibana/plugins/visualize/editor/editor.html @@ -64,7 +64,7 @@ - @@ -75,10 +75,10 @@ - + - + diff --git a/src/kibana/plugins/visualize/editor/editor.js b/src/kibana/plugins/visualize/editor/editor.js index 18552ee2f96b31..fd252f79019e7c 100644 --- a/src/kibana/plugins/visualize/editor/editor.js +++ b/src/kibana/plugins/visualize/editor/editor.js @@ -112,9 +112,6 @@ define(function (require) { $scope.state = $state; $scope.conf = _.pick($scope, 'doSave', 'savedVis', 'shareData'); $scope.configTemplate = configTemplate; - $scope.toggleShare = _.bindKey(configTemplate, 'toggle', 'share'); - $scope.toggleSave = _.bindKey(configTemplate, 'toggle', 'save'); - $scope.toggleLoad = _.bindKey(configTemplate, 'toggle', 'load'); $scope.linked = !!savedVis.savedSearchId; if ($scope.linked) { From 6c5bf5f36f2bc0acec555ad073c23f7c46ebfdae Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 16:09:37 -0700 Subject: [PATCH 127/142] [visualize/editor] track 'linked' in state, reload on back button --- .../plugins/visualize/editor/editor.html | 15 +++++-- src/kibana/plugins/visualize/editor/editor.js | 39 +++++++++---------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html index 243cac584a25be..db5e186493f038 100644 --- a/src/kibana/plugins/visualize/editor/editor.html +++ b/src/kibana/plugins/visualize/editor/editor.html @@ -2,7 +2,7 @@
-
@@ -12,11 +12,14 @@ {{ savedVis.savedSearchId | json}}
-
+
Unlinked!
- +
-
+
diff --git a/src/kibana/plugins/visualize/editor/editor.js b/src/kibana/plugins/visualize/editor/editor.js index 18552ee2f96b31..acace22452b707 100644 --- a/src/kibana/plugins/visualize/editor/editor.js +++ b/src/kibana/plugins/visualize/editor/editor.js @@ -80,9 +80,10 @@ define(function (require) { docTitle.change(savedVis.title); } - var $state = (function initState() { + var $state = $scope.$state = (function initState() { var savedVisState = vis.getState(); var stateDefaults = { + linked: !!savedVis.savedSearchId, query: searchSource.getOwn('query') || {query_string: {query: '*'}}, filters: searchSource.getOwn('filter') || [], vis: savedVisState @@ -116,18 +117,6 @@ define(function (require) { $scope.toggleSave = _.bindKey(configTemplate, 'toggle', 'save'); $scope.toggleLoad = _.bindKey(configTemplate, 'toggle', 'load'); - $scope.linked = !!savedVis.savedSearchId; - if ($scope.linked) { - // possibly left over state from unsaved unlinking - delete $state.query; - $state.filters = searchSource.getOwn('filter'); - } else { - $state.query = $state.query || searchSource.get('query'); - courier.setRootSearchSource(searchSource); - searchSource.set('query', $state.query); - searchSource.set('filter', $state.filters); - } - editableVis.listeners.click = vis.listeners.click = filterBarClickHandler($state); editableVis.listeners.brush = vis.listeners.brush = brushEvent; @@ -166,6 +155,12 @@ define(function (require) { }); $scope.$listen($state, 'fetch_with_changes', function (keys) { + if (_.contains(keys, 'linked') && $state.linked === true) { + // abort and reload route + $route.reload(); + return; + } + if (_.contains(keys, 'vis')) { // only update when we need to, otherwise colors change and we // risk loosing an in-progress result @@ -174,7 +169,7 @@ define(function (require) { } // we use state to track query, must write before we fetch - if ($state.query && !$scope.linked) { + if ($state.query && !$state.linked) { searchSource.set('query', $state.query); } else { searchSource.set('query', null); @@ -187,7 +182,6 @@ define(function (require) { } $scope.fetch(); - }); $scope.$listen(timefilter, 'update', _.bindKey($scope, 'fetch')); @@ -204,7 +198,7 @@ define(function (require) { $scope.fetch = function () { $state.save(); searchSource.set('filter', $state.filters); - if (!$scope.linked) searchSource.set('query', $state.query); + if (!$state.linked) searchSource.set('query', $state.query); if ($scope.vis.type.requiresSearch) courier.fetch(); }; @@ -238,11 +232,14 @@ define(function (require) { }; $scope.unlink = function () { + if (!$state.linked) return; + + $state.linked = false; var parent = searchSource.getParent(true); var parentsParent = parent.getParent(true); // display unlinking for 2 seconds, unless it is double clicked - $scope.unlinking = $timeout($scope.doneUnlinking, 2000); + $scope.unlinking = $timeout($scope.clearUnlinking, 2000); delete savedVis.savedSearchId; parent.set('filter', _.union(searchSource.getOwn('filter'), parent.getOwn('filter'))); @@ -257,9 +254,11 @@ define(function (require) { searchSource.inherits(parentsParent); }; - $scope.doneUnlinking = function () { - $scope.unlinking = clearTimeout($scope.unlinking); - $scope.linked = false; + $scope.clearUnlinking = function () { + if ($scope.unlinking) { + $timeout.cancel($scope.unlinking); + $scope.unlinking = null; + } }; function transferVisState(fromVis, toVis, fetch) { From 063b012cc89879fcbd55e3bb9031f6df234dfdaa Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 9 Jan 2015 16:18:49 -0700 Subject: [PATCH 128/142] [kibana] nav links to lastPath only when the app isn't active --- src/kibana/plugins/kibana/_apps.js | 10 +++++++--- src/kibana/plugins/kibana/kibana.html | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/kibana/plugins/kibana/_apps.js b/src/kibana/plugins/kibana/_apps.js index 003ad5b3862651..4f39c25fc5c3bd 100644 --- a/src/kibana/plugins/kibana/_apps.js +++ b/src/kibana/plugins/kibana/_apps.js @@ -28,12 +28,16 @@ define(function (require) { function onRouteChange() { var route = $location.path().split(/\//); - var app = $rootScope.activeApp = _.find($scope.apps, { id: route[1] }); + $scope.apps.forEach(function (app) { + if (app.active = app.id === route[1]) { + $rootScope.activeApp = app; + } + }); - if (!app || $scope.appEmbedded) return; + if (!$rootScope.activeApp || $scope.appEmbedded) return; // Record the last URL w/ state of the app, use for tab. - setLastPath(app, globalState.removeFromUrl($location.url())); + setLastPath($rootScope.activeApp, globalState.removeFromUrl($location.url())); } $rootScope.$on('$routeChangeSuccess', onRouteChange); diff --git a/src/kibana/plugins/kibana/kibana.html b/src/kibana/plugins/kibana/kibana.html index dc15756a8a5762..fce1dd79a99d83 100644 --- a/src/kibana/plugins/kibana/kibana.html +++ b/src/kibana/plugins/kibana/kibana.html @@ -18,8 +18,8 @@