Skip to content

Commit b16bb24

Browse files
authored
[Search][Discover] Restore searchSessionId from URL (#81633) (#83162)
1 parent ff48a84 commit b16bb24

File tree

7 files changed

+378
-5
lines changed

7 files changed

+378
-5
lines changed

src/plugins/discover/public/application/angular/discover.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ import {
8383
MODIFY_COLUMNS_ON_SWITCH,
8484
} from '../../../common';
8585
import { METRIC_TYPE } from '@kbn/analytics';
86+
import { SEARCH_SESSION_ID_QUERY_PARAM } from '../../url_generator';
87+
import { removeQueryParam, getQueryParams } from '../../../../kibana_utils/public';
8688

8789
const fetchStatuses = {
8890
UNINITIALIZED: 'uninitialized',
@@ -91,6 +93,9 @@ const fetchStatuses = {
9193
ERROR: 'error',
9294
};
9395

96+
const getSearchSessionIdFromURL = (history) =>
97+
getQueryParams(history.location)[SEARCH_SESSION_ID_QUERY_PARAM];
98+
9499
const app = getAngularModule();
95100

96101
app.config(($routeProvider) => {
@@ -208,6 +213,8 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise
208213
};
209214

210215
const history = getHistory();
216+
// used for restoring background session
217+
let isInitialSearch = true;
211218

212219
const {
213220
appStateContainer,
@@ -798,17 +805,30 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise
798805
if (abortController) abortController.abort();
799806
abortController = new AbortController();
800807

801-
const sessionId = data.search.session.start();
808+
const searchSessionId = (() => {
809+
const searchSessionIdFromURL = getSearchSessionIdFromURL(history);
810+
if (searchSessionIdFromURL) {
811+
if (isInitialSearch) {
812+
data.search.session.restore(searchSessionIdFromURL);
813+
isInitialSearch = false;
814+
return searchSessionIdFromURL;
815+
} else {
816+
// navigating away from background search
817+
removeQueryParam(history, SEARCH_SESSION_ID_QUERY_PARAM);
818+
}
819+
}
820+
return data.search.session.start();
821+
})();
802822

803823
$scope
804824
.updateDataSource()
805825
.then(setupVisualization)
806826
.then(function () {
807827
$scope.fetchStatus = fetchStatuses.LOADING;
808-
logInspectorRequest();
828+
logInspectorRequest({ searchSessionId });
809829
return $scope.searchSource.fetch({
810830
abortSignal: abortController.signal,
811-
sessionId,
831+
sessionId: searchSessionId,
812832
});
813833
})
814834
.then(onResults)
@@ -900,15 +920,15 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise
900920
$scope.fetchStatus = fetchStatuses.COMPLETE;
901921
}
902922

903-
function logInspectorRequest() {
923+
function logInspectorRequest({ searchSessionId = null } = { searchSessionId: null }) {
904924
inspectorAdapters.requests.reset();
905925
const title = i18n.translate('discover.inspectorRequestDataTitle', {
906926
defaultMessage: 'data',
907927
});
908928
const description = i18n.translate('discover.inspectorRequestDescription', {
909929
defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
910930
});
911-
inspectorRequest = inspectorAdapters.requests.start(title, { description });
931+
inspectorRequest = inspectorAdapters.requests.start(title, { description, searchSessionId });
912932
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
913933
$scope.searchSource.getSearchRequestBody().then((body) => {
914934
inspectorRequest.json(body);

src/plugins/discover/public/url_generator.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ describe('Discover url generator', () => {
212212
});
213213
});
214214

215+
test('can specify a search session id', async () => {
216+
const { generator } = await setup();
217+
const url = await generator.createUrl({
218+
searchSessionId: '__test__',
219+
});
220+
expect(url).toMatchInlineSnapshot(`"xyz/app/discover#/?_g=()&_a=()&searchSessionId=__test__"`);
221+
expect(url).toContain('__test__');
222+
});
223+
215224
describe('useHash property', () => {
216225
describe('when default useHash is set to false', () => {
217226
test('when using default, sets index pattern ID in the generated URL', async () => {

src/plugins/discover/public/url_generator.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,20 @@ export interface DiscoverUrlGeneratorState {
6767
* whether to hash the data in the url to avoid url length issues.
6868
*/
6969
useHash?: boolean;
70+
71+
/**
72+
* Background search session id
73+
*/
74+
searchSessionId?: string;
7075
}
7176

7277
interface Params {
7378
appBasePath: string;
7479
useHash: boolean;
7580
}
7681

82+
export const SEARCH_SESSION_ID_QUERY_PARAM = 'searchSessionId';
83+
7784
export class DiscoverUrlGenerator
7885
implements UrlGeneratorsDefinition<typeof DISCOVER_APP_URL_GENERATOR> {
7986
constructor(private readonly params: Params) {}
@@ -88,6 +95,7 @@ export class DiscoverUrlGenerator
8895
savedSearchId,
8996
timeRange,
9097
useHash = this.params.useHash,
98+
searchSessionId,
9199
}: DiscoverUrlGeneratorState): Promise<string> => {
92100
const savedSearchPath = savedSearchId ? encodeURIComponent(savedSearchId) : '';
93101
const appState: {
@@ -111,6 +119,10 @@ export class DiscoverUrlGenerator
111119
url = setStateToKbnUrl<QueryState>('_g', queryState, { useHash }, url);
112120
url = setStateToKbnUrl('_a', appState, { useHash }, url);
113121

122+
if (searchSessionId) {
123+
url = `${url}&${SEARCH_SESSION_ID_QUERY_PARAM}=${searchSessionId}`;
124+
}
125+
114126
return url;
115127
};
116128
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
import expect from '@kbn/expect';
7+
import { FtrProviderContext } from '../../ftr_provider_context';
8+
9+
export default function ({ getPageObjects, getService }: FtrProviderContext) {
10+
const esArchiver = getService('esArchiver');
11+
const queryBar = getService('queryBar');
12+
const testSubjects = getService('testSubjects');
13+
const browser = getService('browser');
14+
const inspector = getService('inspector');
15+
const PageObjects = getPageObjects(['discover', 'common', 'timePicker', 'header']);
16+
17+
describe('discover async search', () => {
18+
before(async () => {
19+
await esArchiver.loadIfNeeded('logstash_functional');
20+
await esArchiver.load('discover/default');
21+
await PageObjects.common.navigateToApp('discover');
22+
await PageObjects.timePicker.setDefaultAbsoluteRange();
23+
await PageObjects.header.waitUntilLoadingHasFinished();
24+
});
25+
26+
it('search session id should change between searches', async () => {
27+
const searchSessionId1 = await getSearchSessionId();
28+
expect(searchSessionId1).not.to.be.empty();
29+
await queryBar.clickQuerySubmitButton();
30+
const searchSessionId2 = await getSearchSessionId();
31+
expect(searchSessionId2).not.to.be(searchSessionId1);
32+
});
33+
34+
// NOTE: this test will be revised when
35+
// `searchSessionId` functionality actually works
36+
it('search session id should be picked up from the URL', async () => {
37+
const url = await browser.getCurrentUrl();
38+
const fakeSearchSessionId = '__test__';
39+
const savedSessionURL = url + `&searchSessionId=${fakeSearchSessionId}`;
40+
await browser.navigateTo(savedSessionURL);
41+
await PageObjects.header.waitUntilLoadingHasFinished();
42+
const searchSessionId1 = await getSearchSessionId();
43+
expect(searchSessionId1).to.be(fakeSearchSessionId);
44+
await queryBar.clickQuerySubmitButton();
45+
const searchSessionId2 = await getSearchSessionId();
46+
expect(searchSessionId2).not.to.be(searchSessionId1);
47+
});
48+
});
49+
50+
async function getSearchSessionId(): Promise<string> {
51+
await inspector.open();
52+
const searchSessionId = await (
53+
await testSubjects.find('inspectorRequestSearchSessionId')
54+
).getAttribute('data-search-session-id');
55+
await inspector.close();
56+
return searchSessionId;
57+
}
58+
}

x-pack/test/functional/apps/discover/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
1616
loadTestFile(require.resolve('./error_handling'));
1717
loadTestFile(require.resolve('./visualize_field'));
1818
loadTestFile(require.resolve('./value_suggestions'));
19+
loadTestFile(require.resolve('./async_search'));
1920
});
2021
}
1.09 KB
Binary file not shown.

0 commit comments

Comments
 (0)