Merge branch 'master' of github.com:elasticsearch/kibana into fix/discover_segmented_hit_count

This commit is contained in:
Rashid Khan 2015-03-30 08:39:28 -07:00
commit b03fadbebb
13 changed files with 257 additions and 153 deletions

View file

@ -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();
});
});
};

View file

@ -74,4 +74,4 @@ define(function (require) {
}
};
});
});
});

View file

@ -3,7 +3,7 @@
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<link rel="shortcut icon" href="styles/theme/elk.ico">
<title>Kibana 4</title>

View file

@ -34,16 +34,40 @@
<button ng-click="newDashboard()" aria-label="New Dashboard"><i aria-hidden="true" class="fa fa-file-new-o"></i></button>
</kbn-tooltip>
<kbn-tooltip text="Save Dashboard" placement="bottom" append-to-body="1">
<button aria-label="Save Dashboard" aria-haspopup="true" aria-expanded="{{toggleSaveDashboard}}" ng-click="configTemplate.toggle('save'); toggleSaveDashboard = !toggleSaveDashboard"><i aria-hidden="true" class="fa fa-save"></i></button>
<button
aria-label="Save Dashboard"
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('save') }}"
ng-click="configTemplate.toggle('save');">
<i aria-hidden="true" class="fa fa-save"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Load Saved Dashboard" placement="bottom" append-to-body="1">
<button aria-label="Load Saved Dashboard" aria-haspopup="true" aria-expanded="{{toggleLoadSavedDashboard}}" ng-click="configTemplate.toggle('load'); toggleLoadSavedDashboard = !toggleLoadSavedDashboard"><i aria-hidden="true" class="fa fa-folder-open-o"></i></button>
<button
aria-label="Load Saved Dashboard"
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('load') }}"
ng-click="configTemplate.toggle('load');">
<i aria-hidden="true" class="fa fa-folder-open-o"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Share" placement="bottom" append-to-body="1">
<button aria-label="Share Dashboard" aria-haspopup="true" aria-expanded="{{toggleShareDashboard}}" ng-click="configTemplate.toggle('share'); toggleShareDashboard = !toggleShareDashboard"><i aria-hidden="true" class="fa fa-external-link"></i></button>
<button
aria-label="Share Dashboard"
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('share') }}"
ng-click="configTemplate.toggle('share');">
<i aria-hidden="true" class="fa fa-external-link"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Add Visualization" placement="bottom" append-to-body="1">
<button aria-label="Add Visualization" aria-haspopup="true" aria-expanded="{{toggleAddVisualization}}" ng-click="configTemplate.toggle('pickVis'); toggleAddVisualization = !toggleAddVisualization"><i aria-hidden="true" class="fa fa-plus-circle"></i></button>
<button
aria-label="Add Visualization"
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('pickVis') }}"
ng-click="configTemplate.toggle('pickVis');">
<i aria-hidden="true" class="fa fa-plus-circle"></i>
</button>
</kbn-tooltip>
</div>
</navbar>

View file

@ -1,7 +1,7 @@
<form ng-submit="opts.save()" role="form">
<div class="form-group">
<label for="dashboardTitle">Save As</label>
<input id="dashboardTitle" type="text" ng-model="opts.dashboard.title" class="form-control" placeholder="Dashboard title" input-focus>
<input id="dashboardTitle" type="text" ng-model="opts.dashboard.title" class="form-control" placeholder="Dashboard title" input-focus="select">
</div>
<button type="submit" ng-disabled="!opts.dashboard.title" class="btn btn-primary" aria-label="Save dashboard">Save</button>
</form>

View file

@ -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',

View file

@ -24,21 +24,34 @@
<div class="button-group" role="toolbar">
<kbn-tooltip text="New Search" placement="bottom" append-to-body="1">
<button ng-click="newQuery()" aria-label="New Search"><i aria-hidden="true" class="fa fa-file-new-o"></i></button>
<button
ng-click="newQuery()"
aria-label="New Search">
<i aria-hidden="true" class="fa fa-file-new-o"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Save Search" placement="bottom" append-to-body="1">
<button aria-haspopup="true" aria-expanded="{{toggleSaveSearch}}" ng-click="configTemplate.toggle('save'); toggleSaveSearch = !toggleSaveSearch" aria-label="Save Search"><i aria-hidden="true" class="fa fa-save"></i></button>
<button
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('save') }}"
ng-click="configTemplate.toggle('save');"
aria-label="Save Search">
<i aria-hidden="true" class="fa fa-save"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Load Saved Search" placement="bottom" append-to-body="1">
<button aria-haspopup="true" aria-expanded="{{toggleLoadSavedSearch}}" ng-click="configTemplate.toggle('load'); toggleLoadSavedSearch = !toggleLoadSavedSearch" aria-label="Load Saved Search"><i aria-hidden="true" class="fa fa-folder-open-o"></i></button>
</kbn-tooltip>
<kbn-tooltip text="Settings" placement="bottom" append-to-body="1">
<button aria-haspopup="true" aria-expanded="{{toggleSettings}}" ng-click="configTemplate.toggle('config'); toggleSettings = !toggleSettings" aria-label="Settings"><i aria-hidden="true" class="fa fa-gear"></i></button>
<button
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('load') }}"
ng-click="configTemplate.toggle('load');"
aria-label="Load Saved Search">
<i aria-hidden="true" class="fa fa-folder-open-o"></i>
</button>
</kbn-tooltip>
</div>
</navbar>
<config config-template="configTemplate" config-object="opts" config-close="configClose" config-submit="fetch"></config>
<config config-template="configTemplate" config-object="opts" config-close="configClose"></config>
<div class="container-fluid" role="main">
<div class="row">
@ -65,7 +78,7 @@
<span bindonce bo-bind="opts.savedSearch.title"></span>
<i aria-label="Reload saved query" tooltip="Reload saved query" ng-click="resetQuery();" class="fa fa-undo small"></i>
</span>
<strong class="discover-info-hits">{{(hits || 0) | number:0}}</strong>
<strong class="discover-info-hits">{{(hits || 0) | number:0}}</strong>
<ng-pluralize count="hits" when="{'1':'hit', 'other':'hits'}"></ng-pluralize>
</div>

View file

@ -1 +1,3 @@
<saved-object-finder type="searches"></saved-object-finder>
<form role="form" class="container-fluid" ng-submit="fetch()">
<saved-object-finder type="searches"></saved-object-finder>
</form>

View file

@ -1,15 +1,17 @@
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="SaveSearch" class="control-label">Save Search</label>
<input id="SaveSearch" ng-model="opts.savedSearch.title" input-focus="select" class="form-control" placeholder="Name this search...">
</div>
<div class="form-group">
<button ng-click="opts.saveDataSource()" ng-disabled="!opts.savedSearch.title" type="submit" class="btn btn-primary">
Save
</button>
<form role="form" class="container-fluid" ng-submit="opts.saveDataSource()">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="SaveSearch" class="control-label">Save Search</label>
<input id="SaveSearch" ng-model="opts.savedSearch.title" input-focus="select" class="form-control" placeholder="Name this search...">
</div>
<div class="form-group">
<button ng-disabled="!opts.savedSearch.title" type="submit" class="btn btn-primary">
Save
</button>
</div>
</div>
</div>
</div>
</div>
</form>

View file

@ -28,7 +28,7 @@
</li>
<li ng-if="setupComplete" ng-show="timefilter.enabled" class="navbar-timepicker-container">
<a ng-click="toggleTimepicker()" id="timepicker" aria-haspopup="true" aria-expanded="false">
<a ng-click="toggleTimepicker()" aria-haspopup="true" aria-expanded="false">
<span ng-show="timefilter.refreshInterval.value > 0" class="navbar-timepicker-auto-refresh-desc">
{{timefilter.refreshInterval.display}}
<i aria-hidden="true" class="fa fa-rotate-right"></i>

View file

@ -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
};
}
});
});

View file

@ -82,13 +82,29 @@
</kbn-tooltip>
<kbn-tooltip text="Load Saved Visualization" placement="bottom" append-to-body="1">
<button ng-click="configTemplate.toggle('load')" aria-label="Load Saved Visualization"><i aria-hidden="true" class="fa fa-folder-open-o"></i></button>
<button
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('load') }}"
ng-click="configTemplate.toggle('load')"
aria-label="Load Saved Visualization">
<i aria-hidden="true" class="fa fa-folder-open-o"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Share Visualization" placement="bottom" append-to-body="1">
<button ng-click="configTemplate.toggle('share')" aria-label="Share Visualization"><i aria-hidden="true" class="fa fa-external-link"></i></button>
<button
aria-haspopup="true"
aria-expanded="{{ configTemplate.is('share') }}"
ng-click="configTemplate.toggle('share')"
aria-label="Share Visualization">
<i aria-hidden="true" class="fa fa-external-link"></i>
</button>
</kbn-tooltip>
<kbn-tooltip text="Refresh" placement="bottom" append-to-body="1">
<button ng-click="fetch()" aria-label="Refresh"><i aria-hidden="true" class="fa fa-refresh"></i></button>
<button
ng-click="fetch()"
aria-label="Refresh">
<i aria-hidden="true" class="fa fa-refresh"></i>
</button>
</kbn-tooltip>
</div>
</navbar>

View file

@ -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;
};