mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Since there will soon be a pre-flight request to elasticsearch on certain index patterns when trying to determine which indices match, the conversion must now happen asynchronously. The function now returns a promise that is fulfilled with the matching array of index names.
122 lines
3.6 KiB
JavaScript
122 lines
3.6 KiB
JavaScript
define(function (require) {
|
|
var _ = require('lodash');
|
|
var $ = require('jquery');
|
|
|
|
require('ui/debounce');
|
|
|
|
require('ui/modules')
|
|
.get('kibana')
|
|
.directive('validateQuery', function (es, $compile, timefilter, kbnIndex, debounce, Promise, Private) {
|
|
var fromUser = Private(require('ui/validate_query/lib/from_user'));
|
|
var toUser = require('ui/validate_query/lib/to_user');
|
|
|
|
return {
|
|
restrict: 'A',
|
|
require: 'ngModel',
|
|
scope: {
|
|
'ngModel': '=',
|
|
'queryInput': '=?',
|
|
},
|
|
link: function ($scope, elem, attr, ngModel) {
|
|
|
|
// track request so we can abort it if needed
|
|
var request = {};
|
|
|
|
var errorElem = $('<i tooltip={{tooltipMsg}} class="fa fa-ban input-error"></i>').hide();
|
|
$compile(errorElem)($scope);
|
|
|
|
var init = function () {
|
|
elem.after(errorElem);
|
|
$scope.ngModel = fromUser($scope.ngModel);
|
|
validator($scope.ngModel);
|
|
};
|
|
|
|
function validator(query) {
|
|
if (request.abort) request.abort();
|
|
|
|
var prepare = $scope.queryInput ? useSearchSource : useDefaults;
|
|
|
|
request = prepare().then(sendRequest);
|
|
|
|
function useSearchSource() {
|
|
var pattern = $scope.queryInput.get('index');
|
|
|
|
if (_.isString(pattern)) {
|
|
return Promise.resolve({ index: pattern });
|
|
} else if (_.isFunction(_.get(pattern, 'toIndexList'))) {
|
|
return pattern.toIndexList().then(function (indexList) {
|
|
return { index: indexList };
|
|
});
|
|
} else {
|
|
return useDefaults();
|
|
}
|
|
}
|
|
|
|
function useDefaults() {
|
|
return Promise.resolve({
|
|
index: kbnIndex,
|
|
type: '__kibanaQueryValidator'
|
|
});
|
|
}
|
|
|
|
function sendRequest(config) {
|
|
return es.indices.validateQuery({
|
|
index: config.index,
|
|
type: config.type,
|
|
explain: true,
|
|
ignoreUnavailable: true,
|
|
body: {
|
|
query: query || { match_all: {} }
|
|
}
|
|
})
|
|
.then(success, error);
|
|
}
|
|
|
|
function error(resp) {
|
|
var msg;
|
|
|
|
ngModel.$setValidity('queryInput', false);
|
|
|
|
if (resp.explanations && resp.explanations[0]) {
|
|
msg = resp.explanations[0].error;
|
|
} else {
|
|
msg = resp.body.error;
|
|
}
|
|
|
|
$scope.tooltipMsg = msg;
|
|
errorElem.show();
|
|
|
|
return undefined;
|
|
}
|
|
|
|
function success(resp) {
|
|
if (resp.valid) {
|
|
ngModel.$setValidity('queryInput', true);
|
|
errorElem.hide();
|
|
return query;
|
|
} else {
|
|
return error(resp);
|
|
}
|
|
}
|
|
}
|
|
|
|
var debouncedValidator = debounce(validator, 300, {
|
|
leading: true,
|
|
trailing: true
|
|
});
|
|
|
|
ngModel.$parsers.push(fromUser);
|
|
ngModel.$formatters.push(toUser);
|
|
|
|
// Use a model watch instead of parser/formatter. Parsers require the
|
|
// user to actually enter input, which may not happen if the back button is clicked
|
|
$scope.$watch('ngModel', function (newValue, oldValue) {
|
|
if (newValue === oldValue) return;
|
|
debouncedValidator(newValue);
|
|
});
|
|
|
|
init();
|
|
}
|
|
};
|
|
});
|
|
});
|