mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* Implement inspector for Saved Searches * add inspect top nav to discover app * add functional test, add support for empty results * clean up functional test names * create inspector request before processing response
This commit is contained in:
parent
32f1c1b51f
commit
517947765a
7 changed files with 152 additions and 1 deletions
|
@ -55,6 +55,9 @@ import '../components/fetch_error';
|
|||
import { getPainlessError } from './get_painless_error';
|
||||
import { showShareContextMenu } from 'ui/share';
|
||||
import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing';
|
||||
import { Inspector } from 'ui/inspector';
|
||||
import { RequestAdapter } from 'ui/inspector/adapters';
|
||||
import { getRequestInspectorStats, getResponseInspectorStats } from 'ui/courier/utils/courier_inspector_utils';
|
||||
|
||||
const app = uiModules.get('apps/discover', [
|
||||
'kibana/notify',
|
||||
|
@ -159,6 +162,9 @@ function discoverController(
|
|||
location: 'Discover'
|
||||
});
|
||||
const getUnhashableStates = Private(getUnhashableStatesProvider);
|
||||
const inspectorAdapters = {
|
||||
requests: new RequestAdapter()
|
||||
};
|
||||
|
||||
$scope.getDocLink = getDocLink;
|
||||
$scope.intervalOptions = intervalOptions;
|
||||
|
@ -201,6 +207,15 @@ function discoverController(
|
|||
objectType: 'search',
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'inspect',
|
||||
description: 'Open Inspector for search',
|
||||
testId: 'openInspectorButton',
|
||||
run() {
|
||||
Inspector.open(inspectorAdapters, {
|
||||
title: savedSearch.title
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
// the actual courier.SearchSource
|
||||
|
@ -554,9 +569,38 @@ function discoverController(
|
|||
segmented.setSortFn(sortFn);
|
||||
segmented.setSize($scope.opts.sampleSize);
|
||||
|
||||
let inspectorRequests = [];
|
||||
function logResponseInInspector(resp) {
|
||||
if (inspectorRequests.length > 0) {
|
||||
const inspectorRequest = inspectorRequests.shift();
|
||||
inspectorRequest
|
||||
.stats(getResponseInspectorStats($scope.searchSource, resp))
|
||||
.ok({ json: resp });
|
||||
}
|
||||
}
|
||||
|
||||
// triggered when the status updated
|
||||
segmented.on('status', function (status) {
|
||||
$scope.fetchStatus = status;
|
||||
if (status.complete === 0) {
|
||||
// starting new segmented search request
|
||||
inspectorAdapters.requests.reset();
|
||||
inspectorRequests = [];
|
||||
}
|
||||
|
||||
if (status.remaining > 0) {
|
||||
const inspectorRequest = inspectorAdapters.requests.start(
|
||||
`Segment ${$scope.fetchStatus.complete}`,
|
||||
{
|
||||
description: `This request queries Elasticsearch to fetch the data for the search.`,
|
||||
});
|
||||
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
|
||||
$scope.searchSource.getSearchRequestBody().then(body => {
|
||||
inspectorRequest.json(body);
|
||||
});
|
||||
inspectorRequests.push(inspectorRequest);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
segmented.on('first', function () {
|
||||
|
@ -564,6 +608,7 @@ function discoverController(
|
|||
});
|
||||
|
||||
segmented.on('segment', (resp) => {
|
||||
logResponseInInspector(resp);
|
||||
if (resp._shards.failed > 0) {
|
||||
$scope.failures = _.union($scope.failures, resp._shards.failures);
|
||||
$scope.failures = _.uniq($scope.failures, false, function (failure) {
|
||||
|
@ -572,6 +617,10 @@ function discoverController(
|
|||
}
|
||||
});
|
||||
|
||||
segmented.on('emptySegment', function (resp) {
|
||||
logResponseInInspector(resp);
|
||||
});
|
||||
|
||||
segmented.on('mergedSegment', function (merged) {
|
||||
$scope.mergedEsResp = merged;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import { Embeddable } from 'ui/embeddable';
|
|||
import searchTemplate from './search_template.html';
|
||||
import * as columnActions from 'ui/doc_table/actions/columns';
|
||||
import { getTime } from 'ui/timefilter/get_time';
|
||||
import { RequestAdapter } from 'ui/inspector/adapters';
|
||||
|
||||
export class SearchEmbeddable extends Embeddable {
|
||||
constructor({ onEmbeddableStateChanged, savedSearch, editUrl, loader, $rootScope, $compile }) {
|
||||
|
@ -38,6 +39,13 @@ export class SearchEmbeddable extends Embeddable {
|
|||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
this.customization = {};
|
||||
this.inspectorAdaptors = {
|
||||
requests: new RequestAdapter()
|
||||
};
|
||||
}
|
||||
|
||||
getInspectorAdapters() {
|
||||
return this.inspectorAdaptors;
|
||||
}
|
||||
|
||||
emitEmbeddableStateChange(embeddableState) {
|
||||
|
@ -84,6 +92,7 @@ export class SearchEmbeddable extends Embeddable {
|
|||
|
||||
this.searchScope.description = this.savedSearch.description;
|
||||
this.searchScope.searchSource = this.savedSearch.searchSource;
|
||||
this.searchScope.inspectorAdapters = this.inspectorAdaptors;
|
||||
|
||||
const timeRangeSearchSource = this.searchScope.searchSource.create();
|
||||
timeRangeSearchSource.setField('filter', () => {
|
||||
|
|
|
@ -13,5 +13,6 @@
|
|||
on-move-column="moveColumn"
|
||||
on-remove-column="removeColumn"
|
||||
data-test-subj="embeddedSavedSearchDocTable"
|
||||
inspector-adapters="inspectorAdapters"
|
||||
>
|
||||
</doc-table>
|
||||
|
|
|
@ -233,7 +233,7 @@ export function SegmentedSearchRequestProvider(Private, config) {
|
|||
this.resp = _.omit(this._mergedResp, '_bucketIndex');
|
||||
|
||||
if (firstHits) this._handle.emit('first', seg);
|
||||
if (gotHits) this._handle.emit('segment', seg);
|
||||
gotHits ? this._handle.emit('segment', seg) : this._handle.emit('emptySegment', seg);
|
||||
if (haveHits) this._handle.emit('mergedSegment', this.resp);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import './components/table_header';
|
|||
import './components/table_row';
|
||||
import { dispatchRenderComplete } from '../render_complete';
|
||||
import { uiModules } from '../modules';
|
||||
import { getRequestInspectorStats, getResponseInspectorStats } from '../courier/utils/courier_inspector_utils';
|
||||
|
||||
import { getLimitedSearchResultsMessage } from './doc_table_strings';
|
||||
|
||||
|
@ -49,6 +50,7 @@ uiModules.get('kibana')
|
|||
onChangeSortOrder: '=?',
|
||||
onMoveColumn: '=?',
|
||||
onRemoveColumn: '=?',
|
||||
inspectorAdapters: '=?',
|
||||
},
|
||||
link: function ($scope, $el) {
|
||||
const notify = new Notifier();
|
||||
|
@ -132,7 +134,26 @@ uiModules.get('kibana')
|
|||
}
|
||||
|
||||
function startSearching() {
|
||||
let inspectorRequest = undefined;
|
||||
if (_.has($scope, 'inspectorAdapters.requests')) {
|
||||
$scope.inspectorAdapters.requests.reset();
|
||||
inspectorRequest = $scope.inspectorAdapters.requests.start('Data', {
|
||||
description: `This request queries Elasticsearch to fetch the data for the search.`,
|
||||
});
|
||||
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
|
||||
$scope.searchSource.getSearchRequestBody().then(body => {
|
||||
inspectorRequest.json(body);
|
||||
});
|
||||
}
|
||||
$scope.searchSource.onResults()
|
||||
.then(resp => {
|
||||
if (inspectorRequest) {
|
||||
inspectorRequest
|
||||
.stats(getResponseInspectorStats($scope.searchSource, resp))
|
||||
.ok({ json: resp });
|
||||
}
|
||||
return resp;
|
||||
})
|
||||
.then(onResults)
|
||||
.catch(error => {
|
||||
notify.error(error);
|
||||
|
|
70
test/functional/apps/discover/_inspector.js
Normal file
70
test/functional/apps/discover/_inspector.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const PageObjects = getPageObjects(['common', 'header', 'visualize']);
|
||||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
const STATS_ROW_NAME_INDEX = 0;
|
||||
const STATS_ROW_VALUE_INDEX = 1;
|
||||
function getHitCount(requestStats) {
|
||||
const hitsCountStatsRow = requestStats.find((statsRow) => {
|
||||
return statsRow[STATS_ROW_NAME_INDEX] === 'Hits';
|
||||
});
|
||||
return hitsCountStatsRow[STATS_ROW_VALUE_INDEX];
|
||||
}
|
||||
|
||||
describe('inspect', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('logstash_functional');
|
||||
await esArchiver.load('discover');
|
||||
// delete .kibana index and update configDoc
|
||||
await kibanaServer.uiSettings.replace({
|
||||
'dateFormat:tz': 'UTC',
|
||||
'defaultIndex': 'logstash-*'
|
||||
});
|
||||
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await PageObjects.visualize.closeInspector();
|
||||
});
|
||||
|
||||
it('should display request stats with no results', async () => {
|
||||
await PageObjects.visualize.openInspector();
|
||||
const requestStats = await PageObjects.visualize.getInspectorTableData();
|
||||
|
||||
expect(getHitCount(requestStats)).to.be('0');
|
||||
});
|
||||
|
||||
it('should display request stats with results', async () => {
|
||||
await PageObjects.header.setAbsoluteRange('2015-09-19 06:31:44.000', '2015-09-23 18:31:44.000');
|
||||
|
||||
await PageObjects.visualize.openInspector();
|
||||
const requestStats = await PageObjects.visualize.getInspectorTableData();
|
||||
|
||||
expect(getHitCount(requestStats)).to.be('14004');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
|
@ -37,5 +37,6 @@ export default function ({ getService, loadTestFile }) {
|
|||
loadTestFile(require.resolve('./_sidebar'));
|
||||
loadTestFile(require.resolve('./_source_filters'));
|
||||
loadTestFile(require.resolve('./_large_string'));
|
||||
loadTestFile(require.resolve('./_inspector'));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue