diff --git a/src/kibana/components/vislib/components/tooltip/tooltip.js b/src/kibana/components/vislib/components/tooltip/tooltip.js
index 18beebd3e76f..4dd63b6c4182 100644
--- a/src/kibana/components/vislib/components/tooltip/tooltip.js
+++ b/src/kibana/components/vislib/components/tooltip/tooltip.js
@@ -82,14 +82,11 @@ define(function (require) {
// moving between points doesn't make it reposition
$chart.removeData('previousPlacement');
});
- $chart.find('.chart > svg').on('mousemove', function (event) {
- event.stopPropagation();
- });
selection.each(function (d, i) {
var element = d3.select(this);
- function render(event, html) {
+ function render(html) {
allContents = _.filter(allContents, function (content) {
return content.id !== id;
});
@@ -108,7 +105,7 @@ define(function (require) {
$chart: $chart,
$el: $tooltip,
$sizer: $sizer,
- event: event
+ event: d3.event
}, allHtml);
$tooltip
@@ -118,10 +115,6 @@ define(function (require) {
left: placement.left,
top: placement.top
});
- // add a make sure to remove the tooltip when necessary
- $('body').one('mousemove', function (event) {
- render(event);
- });
} else {
$tooltip.css({
visibility: 'hidden',
@@ -134,14 +127,14 @@ define(function (require) {
element
.on('mousemove.tip', function update() {
if (!self.showCondition.call(element, d, i)) {
- return render(d3.event);
+ return render();
}
var events = self.events ? self.events.eventResponse(d, i) : d;
- return render(d3.event, tooltipFormatter(events));
+ return render(tooltipFormatter(events));
})
.on('mouseout.tip', function () {
- render(d3.event);
+ render();
});
});
};
diff --git a/src/kibana/directives/config.js b/src/kibana/directives/config.js
index 2f48bad19bbd..a29a2ff44a55 100644
--- a/src/kibana/directives/config.js
+++ b/src/kibana/directives/config.js
@@ -74,4 +74,4 @@ define(function (require) {
}
};
});
-});
\ No newline at end of file
+});
diff --git a/src/kibana/index.html b/src/kibana/index.html
index 24dbcfd387c6..1d275523b1b9 100644
--- a/src/kibana/index.html
+++ b/src/kibana/index.html
@@ -3,7 +3,7 @@
-
+
Kibana 4
diff --git a/src/kibana/plugins/dashboard/index.html b/src/kibana/plugins/dashboard/index.html
index 1630701ac03e..22664ab85055 100644
--- a/src/kibana/plugins/dashboard/index.html
+++ b/src/kibana/plugins/dashboard/index.html
@@ -34,16 +34,40 @@
-
+
-
+
-
+
-
+
diff --git a/src/kibana/plugins/dashboard/partials/save_dashboard.html b/src/kibana/plugins/dashboard/partials/save_dashboard.html
index 2ddd9921ed3c..344e20306819 100644
--- a/src/kibana/plugins/dashboard/partials/save_dashboard.html
+++ b/src/kibana/plugins/dashboard/partials/save_dashboard.html
@@ -1,7 +1,7 @@
diff --git a/src/kibana/plugins/discover/components/field_chooser/field_chooser.js b/src/kibana/plugins/discover/components/field_chooser/field_chooser.js
index 91b169d35e54..2795d1a3318a 100644
--- a/src/kibana/plugins/discover/components/field_chooser/field_chooser.js
+++ b/src/kibana/plugins/discover/components/field_chooser/field_chooser.js
@@ -128,7 +128,7 @@ define(function (require) {
var type = isGeoPoint ? 'tile_map' : 'histogram';
// If we're visualizing a date field, and our index is time based (and thus has a time filter),
// then run a date histogram
- if (field.type === 'date' && $scope.indexPattern.timeFieldName) {
+ if (field.type === 'date' && $scope.indexPattern.timeFieldName === field.name) {
agg = {
type: 'date_histogram',
schema: 'segment',
diff --git a/src/kibana/plugins/discover/index.html b/src/kibana/plugins/discover/index.html
index 6bcbb946b566..89bafb1a6c65 100644
--- a/src/kibana/plugins/discover/index.html
+++ b/src/kibana/plugins/discover/index.html
@@ -24,21 +24,34 @@
-
+
-
+
-
-
-
-
+
-
+
@@ -65,7 +78,7 @@
- {{(hits || 0) | number:0}}
+ {{(hits || 0) | number:0}}
diff --git a/src/kibana/plugins/discover/partials/load_search.html b/src/kibana/plugins/discover/partials/load_search.html
index 1cfcf3605149..2b66911dbafc 100644
--- a/src/kibana/plugins/discover/partials/load_search.html
+++ b/src/kibana/plugins/discover/partials/load_search.html
@@ -1 +1,3 @@
-
\ No newline at end of file
+
diff --git a/src/kibana/plugins/discover/partials/save_search.html b/src/kibana/plugins/discover/partials/save_search.html
index 7df5cd855e54..ff4aeaa2de93 100644
--- a/src/kibana/plugins/discover/partials/save_search.html
+++ b/src/kibana/plugins/discover/partials/save_search.html
@@ -1,15 +1,17 @@
-
-
-
-
-
-
-
-
+
diff --git a/src/kibana/plugins/kibana/kibana.html b/src/kibana/plugins/kibana/kibana.html
index 998c0e4bfec8..db495f8e661a 100644
--- a/src/kibana/plugins/kibana/kibana.html
+++ b/src/kibana/plugins/kibana/kibana.html
@@ -28,7 +28,7 @@
-
+
{{timefilter.refreshInterval.display}}
diff --git a/src/kibana/plugins/settings/sections/indices/_create.js b/src/kibana/plugins/settings/sections/indices/_create.js
index e6cb4b00d677..6db1de9e6a24 100644
--- a/src/kibana/plugins/settings/sections/indices/_create.js
+++ b/src/kibana/plugins/settings/sections/indices/_create.js
@@ -12,11 +12,12 @@ define(function (require) {
});
require('modules').get('apps/settings')
- .controller('settingsIndicesCreate', function ($scope, kbnUrl, Private, Notifier, indexPatterns, es, config) {
+ .controller('settingsIndicesCreate', function ($scope, kbnUrl, Private, Notifier, indexPatterns, es, config, Promise) {
var notify = new Notifier();
var MissingIndices = errors.IndexPatternMissingIndices;
var refreshKibanaIndex = Private(require('plugins/settings/sections/indices/_refresh_kibana_index'));
var intervals = indexPatterns.intervals;
+ var samplePromise;
// this and child scopes will write pattern vars here
var index = $scope.index = {
@@ -33,83 +34,8 @@ define(function (require) {
index.nameInterval = _.find(index.nameIntervalOptions, { name: 'daily' });
index.timeField = null;
- var updateSamples = function () {
- index.samples = null;
- index.existing = null;
- index.patternErrors = [];
-
- if (!index.nameInterval || !index.name) {
- return;
- }
-
- var pattern = mockIndexPattern(index);
-
- indexPatterns.mapper.getIndicesForIndexPattern(pattern)
- .then(function (existing) {
- var all = existing.all;
- var matches = existing.matches;
- if (all.length) {
- index.existing = {
- class: 'success',
- all: all,
- matches: matches,
- matchPercent: Math.round((matches.length / all.length) * 100) + '%',
- failures: _.difference(all, matches)
- };
- return;
- }
-
- index.patternErrors.push('Pattern does not match any existing indices');
- var radius = Math.round(index.sampleCount / 2);
- var samples = intervals.toIndexList(index.name, index.nameInterval, -radius, radius);
-
- if (_.uniq(samples).length !== samples.length) {
- index.patternErrors.push('Invalid pattern, interval does not create unique index names');
- } else {
- index.samples = samples;
- }
- })
- .catch(notify.error);
- };
-
$scope.refreshFieldList = function () {
- index.dateFields = index.timeField = index.listUsed = null;
- var useIndexList = index.isTimeBased && index.nameIsPattern;
-
- // we don't have enough info to continue
- if (!index.name) {
- index.fetchFieldsError = 'Set an index name first';
- return;
- }
-
- if (useIndexList && !index.nameInterval) {
- index.fetchFieldsError = 'Select the interval at which your indices are populated.';
- return;
- }
-
- return indexPatterns.mapper.clearCache(index.name)
- .then(function () {
- var pattern = mockIndexPattern(index);
-
- return indexPatterns.mapper.getFieldsForIndexPattern(pattern, true)
- .catch(function (err) {
- // TODO: we should probably display a message of some kind
- if (err instanceof MissingIndices) {
- index.fetchFieldsError = 'Unable to fetch mapping. Do you have indices matching the pattern?';
- return [];
- }
-
- throw err;
- });
- })
- .then(function (fields) {
- if (fields.length > 0) {
- index.fetchFieldsError = null;
- index.dateFields = fields.filter(function (field) {
- return field.type === 'date';
- });
- }
- }, notify.fatal);
+ fetchFieldList().then(updateFieldList);
};
$scope.createIndexPattern = function () {
@@ -156,24 +82,6 @@ define(function (require) {
'index.nameIsPattern',
'index.nameInterval.name'
], function (newVal, oldVal) {
-
- function getPatternDefault(interval) {
- switch (interval) {
- case 'hours':
- return '[logstash-]YYYY.MM.DD.HH';
- case 'days':
- return '[logstash-]YYYY.MM.DD';
- case 'weeks':
- return '[logstash-]GGGG.WW';
- case 'months':
- return '[logstash-]YYYY.MM';
- case 'years':
- return '[logstash-]YYYY';
- default:
- return 'logstash-*';
- }
- }
-
var isTimeBased = newVal[0];
var nameIsPattern = newVal[1];
var newDefault = getPatternDefault(newVal[2]);
@@ -194,17 +102,8 @@ define(function (require) {
index.nameInterval = index.nameInterval || intervals.byName['days'];
index.name = index.name || getPatternDefault(index.nameInterval);
}
-
});
- var mockIndexPattern = function (index) {
- // trick the mapper into thinking this is an indexPattern
- return {
- id: index.name,
- intervalName: index.nameInterval
- };
- };
-
$scope.moreSamples = function (andUpdate) {
index.sampleCount += 5;
if (andUpdate) updateSamples();
@@ -213,13 +112,164 @@ define(function (require) {
$scope.$watchMulti([
'index.name',
'index.nameInterval'
- ], updateSamples);
+ ], function (newVal, oldVal) {
+ var lastPromise;
+ samplePromise = lastPromise = updateSamples()
+ .then(function () {
+ promiseMatch(lastPromise, function () {
+ index.samples = null;
+ index.patternErrors = [];
+ });
+ })
+ .catch(function (errors) {
+ promiseMatch(lastPromise, function () {
+ index.existing = null;
+ index.patternErrors = errors;
+ });
+ })
+ .finally(function () {
+ // prevent running when no change happened (ie, first watcher call)
+ if (!_.isEqual(newVal, oldVal)) {
+ fetchFieldList().then(function (results) {
+ if (lastPromise === samplePromise) {
+ updateFieldList(results);
+ }
+ });
+ }
+ });
+ });
$scope.$watchMulti([
- 'index.name',
'index.isTimeBased',
- 'index.nameInterval',
'index.sampleCount'
], $scope.refreshFieldList);
+
+ function updateSamples() {
+ var patternErrors = [];
+
+ if (!index.nameInterval || !index.name) {
+ return Promise.resolve();
+ }
+
+ var pattern = mockIndexPattern(index);
+
+ return indexPatterns.mapper.getIndicesForIndexPattern(pattern)
+ .catch(notify.error)
+ .then(function (existing) {
+ var all = existing.all;
+ var matches = existing.matches;
+ if (all.length) {
+ index.existing = {
+ class: 'success',
+ all: all,
+ matches: matches,
+ matchPercent: Math.round((matches.length / all.length) * 100) + '%',
+ failures: _.difference(all, matches)
+ };
+ return;
+ }
+
+ patternErrors.push('Pattern does not match any existing indices');
+ var radius = Math.round(index.sampleCount / 2);
+ var samples = intervals.toIndexList(index.name, index.nameInterval, -radius, radius);
+
+ if (_.uniq(samples).length !== samples.length) {
+ patternErrors.push('Invalid pattern, interval does not create unique index names');
+ } else {
+ index.samples = samples;
+ }
+
+ throw patternErrors;
+ });
+ }
+
+ function fetchFieldList() {
+ index.dateFields = index.timeField = index.listUsed = null;
+ var useIndexList = index.isTimeBased && index.nameIsPattern;
+ var fetchFieldsError;
+ var dateFields;
+
+ // we don't have enough info to continue
+ if (!index.name) {
+ fetchFieldsError = 'Set an index name first';
+ return;
+ }
+
+ if (useIndexList && !index.nameInterval) {
+ fetchFieldsError = 'Select the interval at which your indices are populated.';
+ return;
+ }
+
+ return indexPatterns.mapper.clearCache(index.name)
+ .then(function () {
+ var pattern = mockIndexPattern(index);
+
+ return indexPatterns.mapper.getFieldsForIndexPattern(pattern, true)
+ .catch(function (err) {
+ // TODO: we should probably display a message of some kind
+ if (err instanceof MissingIndices) {
+ fetchFieldsError = 'Unable to fetch mapping. Do you have indices matching the pattern?';
+ return [];
+ }
+
+ throw err;
+ });
+ })
+ .then(function (fields) {
+ if (fields.length > 0) {
+ fetchFieldsError = null;
+ dateFields = fields.filter(function (field) {
+ return field.type === 'date';
+ });
+ }
+
+ return {
+ fetchFieldsError: fetchFieldsError,
+ dateFields: dateFields
+ };
+ }, notify.fatal);
+ }
+
+ function updateFieldList(results) {
+ index.fetchFieldsError = results.fetchFieldsError;
+ index.dateFields = results.dateFields;
+ }
+
+ function promiseMatch(lastPromise, cb) {
+ if (lastPromise === samplePromise) {
+ cb();
+ } else if (samplePromise != null) {
+ // haven't hit the last promise yet, reset index params
+ index.patternErrors = [];
+ index.samples = null;
+ index.existing = null;
+ index.fetchFieldsError = 'Loading';
+ }
+ }
+
+ function getPatternDefault(interval) {
+ switch (interval) {
+ case 'hours':
+ return '[logstash-]YYYY.MM.DD.HH';
+ case 'days':
+ return '[logstash-]YYYY.MM.DD';
+ case 'weeks':
+ return '[logstash-]GGGG.WW';
+ case 'months':
+ return '[logstash-]YYYY.MM';
+ case 'years':
+ return '[logstash-]YYYY';
+ default:
+ return 'logstash-*';
+ }
+ }
+
+ function mockIndexPattern(index) {
+ // trick the mapper into thinking this is an indexPattern
+ return {
+ id: index.name,
+ intervalName: index.nameInterval
+ };
+ }
});
});
diff --git a/src/kibana/plugins/visualize/editor/editor.html b/src/kibana/plugins/visualize/editor/editor.html
index 6ffca8949971..89d2c68b3cdb 100644
--- a/src/kibana/plugins/visualize/editor/editor.html
+++ b/src/kibana/plugins/visualize/editor/editor.html
@@ -82,13 +82,29 @@
-
+
-
+
-
+
diff --git a/src/kibana/utils/config_template.js b/src/kibana/utils/config_template.js
index 374688356f34..eff806a981a8 100644
--- a/src/kibana/utils/config_template.js
+++ b/src/kibana/utils/config_template.js
@@ -10,7 +10,7 @@ define(function (require) {
function update(newState, name) {
var toUpdate = templates[name];
- var curState = template.current === toUpdate;
+ var curState = template.is(name);
if (newState == null) newState = !curState;
if (newState) {
@@ -22,6 +22,10 @@ define(function (require) {
return newState;
}
+ template.is = function (name) {
+ return template.current === templates[name];
+ };
+
template.toString = function () {
return template.current;
};