[Console] Remove use of jQuery (#127867)

* Remove jquery

* Fixed failing functional test

* Fixed failing jest test

* Lint

* Address comments

* Remove unused imports

* Remove unused imports

* Get http service through context

* Import http to services mock

* Fix use_send_current_request_to_es.test

* Add tests for send_request_to_es logic

* Address comments

* Fix base path

Co-authored-by: Muhammad Ibragimov <muhammad.ibragimov@elastic.co>
This commit is contained in:
Muhammad Ibragimov 2022-04-07 02:38:04 -07:00 committed by GitHub
parent edf6e21941
commit 8a0cc6efcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 332 additions and 201 deletions

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const API_BASE_PATH = '/api/console';

View file

@ -7,3 +7,4 @@
*/
export { MAJOR_VERSION } from './plugin';
export { API_BASE_PATH } from './api';

View file

@ -64,7 +64,7 @@ const inputId = 'ConAppInputTextarea';
function EditorUI({ initialTextValue }: EditorProps) {
const {
services: { history, notifications, settings: settingsService, esHostService },
services: { history, notifications, settings: settingsService, esHostService, http },
docLinkVersion,
} = useServicesContext();
@ -194,7 +194,7 @@ function EditorUI({ initialTextValue }: EditorProps) {
setInputEditor(editor);
setTextArea(editorRef.current!.querySelector('textarea'));
retrieveAutoCompleteInfo(settingsService, settingsService.getAutocomplete());
retrieveAutoCompleteInfo(http, settingsService, settingsService.getAutocomplete());
const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editor);
setupAutosave();
@ -214,6 +214,7 @@ function EditorUI({ initialTextValue }: EditorProps) {
history,
setInputEditor,
settingsService,
http,
]);
useEffect(() => {

View file

@ -8,6 +8,7 @@
import React from 'react';
import type { HttpSetup } from 'kibana/public';
import { AutocompleteOptions, DevToolsSettingsModal } from '../components';
// @ts-ignore
@ -26,13 +27,15 @@ const getAutocompleteDiff = (
};
const refreshAutocompleteSettings = (
http: HttpSetup,
settings: SettingsService,
selectedSettings: DevToolsSettings['autocomplete']
) => {
retrieveAutoCompleteInfo(settings, selectedSettings);
retrieveAutoCompleteInfo(http, settings, selectedSettings);
};
const fetchAutocompleteSettingsIfNeeded = (
http: HttpSetup,
settings: SettingsService,
newSettings: DevToolsSettings,
prevSettings: DevToolsSettings
@ -57,10 +60,10 @@ const fetchAutocompleteSettingsIfNeeded = (
},
{} as DevToolsSettings['autocomplete']
);
retrieveAutoCompleteInfo(settings, changedSettings);
retrieveAutoCompleteInfo(http, settings, changedSettings);
} else if (isPollingChanged && newSettings.polling) {
// If the user has turned polling on, then we'll fetch all selected autocomplete settings.
retrieveAutoCompleteInfo(settings, settings.getAutocomplete());
retrieveAutoCompleteInfo(http, settings, settings.getAutocomplete());
}
}
};
@ -71,14 +74,14 @@ export interface Props {
export function Settings({ onClose }: Props) {
const {
services: { settings },
services: { settings, http },
} = useServicesContext();
const dispatch = useEditorActionContext();
const onSaveSettings = (newSettings: DevToolsSettings) => {
const prevSettings = settings.toJSON();
fetchAutocompleteSettingsIfNeeded(settings, newSettings, prevSettings);
fetchAutocompleteSettingsIfNeeded(http, settings, newSettings, prevSettings);
// Update the new settings in localStorage
settings.updateSettings(newSettings);
@ -96,7 +99,7 @@ export function Settings({ onClose }: Props) {
onClose={onClose}
onSaveSettings={onSaveSettings}
refreshAutocompleteSettings={(selectedSettings) =>
refreshAutocompleteSettings(settings, selectedSettings)
refreshAutocompleteSettings(http, settings, selectedSettings)
}
settings={settings.toJSON()}
/>

View file

@ -37,6 +37,7 @@ export const serviceContextMock = {
history: new HistoryMock(storage),
notifications: notificationServiceMock.createSetupContract(),
objectStorageClient: {} as unknown as ObjectStorageClient,
http,
},
docLinkVersion: 'NA',
theme$: themeServiceMock.create().start().theme$,

View file

@ -8,7 +8,7 @@
import React, { createContext, useContext, useEffect } from 'react';
import { Observable } from 'rxjs';
import { NotificationsSetup, CoreTheme, DocLinksStart } from 'kibana/public';
import type { NotificationsSetup, CoreTheme, DocLinksStart, HttpSetup } from 'kibana/public';
import { History, Settings, Storage } from '../../services';
import { ObjectStorageClient } from '../../../common/types';
@ -23,6 +23,7 @@ interface ContextServices {
objectStorageClient: ObjectStorageClient;
trackUiMetric: MetricsTracker;
esHostService: EsHostService;
http: HttpSetup;
}
export interface ContextValue {

View file

@ -0,0 +1,101 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { ContextValue } from '../../contexts';
jest.mock('./send_request_to_es', () => ({ sendRequestToES: jest.fn(() => Promise.resolve()) }));
import { sendRequestToES } from './send_request_to_es';
import { serviceContextMock } from '../../contexts/services_context.mock';
const mockedSendRequestToES = sendRequestToES as jest.Mock;
describe('sendRequestToES', () => {
let mockContextValue: ContextValue;
beforeEach(() => {
mockContextValue = serviceContextMock.create();
});
afterEach(() => {
jest.resetAllMocks();
});
it('should send request to ES', async () => {
mockedSendRequestToES.mockResolvedValue([
{
response: {
statusCode: 200,
value: '{\n "acknowledged": true \n}',
},
},
]);
const args = {
http: mockContextValue.services.http,
requests: [{ method: 'PUT', url: 'test', data: [] }],
};
const results = await sendRequestToES(args);
const [request] = results;
expect(request.response.statusCode).toEqual(200);
expect(request.response.value).toContain('"acknowledged": true');
expect(mockedSendRequestToES).toHaveBeenCalledWith(args);
expect(mockedSendRequestToES).toHaveBeenCalledTimes(1);
});
it('should send multiple requests to ES', async () => {
mockedSendRequestToES.mockResolvedValue([
{
response: {
statusCode: 200,
},
},
{
response: {
statusCode: 200,
},
},
]);
const args = {
http: mockContextValue.services.http,
requests: [
{ method: 'GET', url: 'test-1', data: [] },
{ method: 'GET', url: 'test-2', data: [] },
],
};
const results = await sendRequestToES(args);
const [firstRequest, secondRequest] = results;
expect(firstRequest.response.statusCode).toEqual(200);
expect(secondRequest.response.statusCode).toEqual(200);
expect(mockedSendRequestToES).toHaveBeenCalledWith(args);
expect(mockedSendRequestToES).toHaveBeenCalledTimes(1);
});
it('should handle errors', async () => {
mockedSendRequestToES.mockRejectedValue({
response: {
statusCode: 500,
statusText: 'error',
},
});
try {
await sendRequestToES({
http: mockContextValue.services.http,
requests: [{ method: 'GET', url: 'test', data: [] }],
});
} catch (error) {
expect(error.response.statusCode).toEqual(500);
expect(error.response.statusText).toEqual('error');
expect(mockedSendRequestToES).toHaveBeenCalledTimes(1);
}
});
});

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
import type { HttpSetup, IHttpFetchError } from 'kibana/public';
import { extractWarningMessages } from '../../../lib/utils';
import { XJson } from '../../../../../es_ui_shared/public';
// @ts-ignore
@ -15,6 +16,7 @@ import { BaseResponseType } from '../../../types';
const { collapseLiteralStrings } = XJson;
export interface EsRequestArgs {
http: HttpSetup;
requests: Array<{ url: string; method: string; data: string[] }>;
}
@ -47,7 +49,7 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
const isMultiRequest = requests.length > 1;
const sendNextRequest = () => {
const sendNextRequest = async () => {
if (reqId !== CURRENT_REQ_ID) {
resolve(results);
return;
@ -65,23 +67,30 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
} // append a new line for bulk requests.
const startTime = Date.now();
es.send(esMethod, esPath, esData).always(
(dataOrjqXHR, textStatus: string, jqXhrORerrorThrown) => {
if (reqId !== CURRENT_REQ_ID) {
return;
}
const xhr = dataOrjqXHR.promise ? dataOrjqXHR : jqXhrORerrorThrown;
try {
const { response, body } = await es.send({
http: args.http,
method: esMethod,
path: esPath,
data: esData,
asResponse: true,
});
if (reqId !== CURRENT_REQ_ID) {
// Skip if previous request is not resolved yet. This can happen when issuing multiple requests at the same time and with slow networks
return;
}
if (response) {
const isSuccess =
typeof xhr.status === 'number' &&
// Things like DELETE index where the index is not there are OK.
((xhr.status >= 200 && xhr.status < 300) || xhr.status === 404);
(response.status >= 200 && response.status < 300) || response.status === 404;
if (isSuccess) {
let value = xhr.responseText;
let value = JSON.stringify(body, null, 2);
const warnings = xhr.getResponseHeader('warning');
const warnings = response.headers.get('warning');
if (warnings) {
const warningMessages = extractWarningMessages(warnings);
value = warningMessages.join('\n') + '\n' + value;
@ -94,9 +103,9 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
results.push({
response: {
timeMs: Date.now() - startTime,
statusCode: xhr.status,
statusText: xhr.statusText,
contentType: xhr.getResponseHeader('Content-Type'),
statusCode: response.status,
statusText: response.statusText,
contentType: response.headers.get('Content-Type') as BaseResponseType,
value,
},
request: {
@ -107,37 +116,47 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
});
// single request terminate via sendNextRequest as well
sendNextRequest();
} else {
let value;
let contentType: string;
if (xhr.responseText) {
value = xhr.responseText; // ES error should be shown
contentType = xhr.getResponseHeader('Content-Type');
} else {
value = 'Request failed to get to the server (status code: ' + xhr.status + ')';
contentType = 'text/plain';
}
if (isMultiRequest) {
value = '# ' + req.method + ' ' + req.url + '\n' + value;
}
reject({
response: {
value,
contentType,
timeMs: Date.now() - startTime,
statusCode: xhr.status,
statusText: xhr.statusText,
},
request: {
data: esData,
method: esMethod,
path: esPath,
},
});
await sendNextRequest();
}
}
);
} catch (error) {
let value;
let contentType: string | null = '';
const { response, body = {} } = error as IHttpFetchError;
if (response) {
const { status, headers } = response;
if (body) {
value = JSON.stringify(body, null, 2); // ES error should be shown
contentType = headers.get('Content-Type');
} else {
value = 'Request failed to get to the server (status code: ' + status + ')';
contentType = headers.get('Content-Type');
}
if (isMultiRequest) {
value = '# ' + req.method + ' ' + req.url + '\n' + value;
}
} else {
value =
"\n\nFailed to connect to Console's backend.\nPlease check the Kibana server is up and running";
}
reject({
response: {
value,
contentType,
timeMs: Date.now() - startTime,
statusCode: error?.response?.status ?? 500,
statusText: error?.response?.statusText ?? 'error',
},
request: {
data: esData,
method: esMethod,
path: esPath,
},
});
}
};
sendNextRequest();

View file

@ -52,7 +52,10 @@ describe('useSendCurrentRequestToES', () => {
const { result } = renderHook(() => useSendCurrentRequestToES(), { wrapper: contexts });
await act(() => result.current());
expect(sendRequestToES).toHaveBeenCalledWith({ requests: ['test'] });
expect(sendRequestToES).toHaveBeenCalledWith({
http: mockContextValue.services.http,
requests: ['test'],
});
// Second call should be the request success
const [, [requestSucceededCall]] = (dispatch as jest.Mock).mock.calls;

View file

@ -21,7 +21,7 @@ import { track } from './track';
export const useSendCurrentRequestToES = () => {
const {
services: { history, settings, notifications, trackUiMetric },
services: { history, settings, notifications, trackUiMetric, http },
theme$,
} = useServicesContext();
@ -46,7 +46,7 @@ export const useSendCurrentRequestToES = () => {
// Fire and forget
setTimeout(() => track(requests, editor, trackUiMetric), 0);
const results = await sendRequestToES({ requests });
const results = await sendRequestToES({ http, requests });
let saveToHistoryError: undefined | Error;
const { historyDisabled } = settings.toJSON();
@ -102,7 +102,7 @@ export const useSendCurrentRequestToES = () => {
// or templates may have changed, so we'll need to update this data. Assume that if
// the user disables polling they're trying to optimize performance or otherwise
// preserve resources, so they won't want this request sent either.
retrieveAutoCompleteInfo(settings, settings.getAutocomplete());
retrieveAutoCompleteInfo(http, settings, settings.getAutocomplete());
}
dispatch({
@ -129,5 +129,5 @@ export const useSendCurrentRequestToES = () => {
});
}
}
}, [dispatch, settings, history, notifications, trackUiMetric, theme$]);
}, [dispatch, http, settings, notifications.toasts, trackUiMetric, history, theme$]);
};

View file

@ -75,6 +75,7 @@ export function renderApp({
notifications,
trackUiMetric,
objectStorageClient,
http,
},
theme$,
}}

View file

@ -6,12 +6,8 @@
* Side Public License, v 1.
*/
import $ from 'jquery';
import { stringify } from 'query-string';
interface SendOptions {
asSystemRequest?: boolean;
}
import type { HttpFetchOptions, HttpResponse, HttpSetup } from 'kibana/public';
import { API_BASE_PATH } from '../../../common/constants';
const esVersion: string[] = [];
@ -24,44 +20,32 @@ export function getContentType(body: unknown) {
return 'application/json';
}
export function send(
method: string,
path: string,
data: string | object,
{ asSystemRequest }: SendOptions = {},
withProductOrigin: boolean = false
) {
const wrappedDfd = $.Deferred();
interface SendProps {
http: HttpSetup;
method: string;
path: string;
data?: string;
asSystemRequest?: boolean;
withProductOrigin?: boolean;
asResponse?: boolean;
}
const options: JQuery.AjaxSettings = {
url:
'../api/console/proxy?' +
stringify({ path, method, ...(withProductOrigin && { withProductOrigin }) }, { sort: false }),
headers: {
'kbn-xsrf': 'kibana',
...(asSystemRequest && { 'kbn-system-request': 'true' }),
},
data,
contentType: getContentType(data),
cache: false,
crossDomain: true,
type: 'POST',
dataType: 'text', // disable automatic guessing
export async function send({
http,
method,
path,
data,
asSystemRequest = false,
withProductOrigin = false,
asResponse = false,
}: SendProps) {
const options: HttpFetchOptions = {
query: { path, method, ...(withProductOrigin && { withProductOrigin }) },
body: data,
asResponse,
asSystemRequest,
};
$.ajax(options).then(
(responseData, textStatus: string, jqXHR: unknown) => {
wrappedDfd.resolveWith({}, [responseData, textStatus, jqXHR]);
},
((jqXHR: { status: number; responseText: string }, textStatus: string, errorThrown: Error) => {
if (jqXHR.status === 0) {
jqXHR.responseText =
"\n\nFailed to connect to Console's backend.\nPlease check the Kibana server is up and running";
}
wrappedDfd.rejectWith({}, [jqXHR, textStatus, errorThrown]);
}) as any
);
return wrappedDfd;
return await http.post<HttpResponse>(`${API_BASE_PATH}/proxy`, options);
}
export function constructESUrl(baseUri: string, path: string) {

View file

@ -6,21 +6,18 @@
* Side Public License, v 1.
*/
import $ from 'jquery';
import _ from 'lodash';
import * as es from '../es/es';
let pollTimeoutId;
let perIndexTypes = {};
let perAliasIndexes = [];
let perAliasIndexes = {};
let legacyTemplates = [];
let indexTemplates = [];
let componentTemplates = [];
let dataStreams = [];
const mappingObj = {};
export function expandAliases(indicesOrAliases) {
// takes a list of indices or aliases or a string which may be either and returns a list of indices
// returns a list for multiple values or a string for a single.
@ -32,7 +29,8 @@ export function expandAliases(indicesOrAliases) {
if (typeof indicesOrAliases === 'string') {
indicesOrAliases = [indicesOrAliases];
}
indicesOrAliases = $.map(indicesOrAliases, function (iOrA) {
indicesOrAliases = indicesOrAliases.map((iOrA) => {
if (perAliasIndexes[iOrA]) {
return perAliasIndexes[iOrA];
}
@ -40,12 +38,14 @@ export function expandAliases(indicesOrAliases) {
});
let ret = [].concat.apply([], indicesOrAliases);
ret.sort();
let last;
ret = $.map(ret, function (v) {
const r = last === v ? null : v;
last = v;
return r;
});
ret = ret.reduce((result, value, index, array) => {
const last = array[index - 1];
if (last !== value) {
result.push(value);
}
return result;
}, []);
return ret.length > 1 ? ret : ret[0];
}
@ -81,8 +81,8 @@ export function getFields(indices, types) {
ret = f ? f : [];
} else {
// filter what we need
$.each(typeDict, function (type, fields) {
if (!types || types.length === 0 || $.inArray(type, types) !== -1) {
Object.entries(typeDict).forEach(([type, fields]) => {
if (!types || types.length === 0 || types.includes(type)) {
ret.push(fields);
}
});
@ -91,11 +91,12 @@ export function getFields(indices, types) {
}
} else {
// multi index mode.
$.each(perIndexTypes, function (index) {
if (!indices || indices.length === 0 || $.inArray(index, indices) !== -1) {
Object.keys(perIndexTypes).forEach((index) => {
if (!indices || indices.length === 0 || indices.includes(index)) {
ret.push(getFields(index, types));
}
});
ret = [].concat.apply([], ret);
}
@ -114,13 +115,19 @@ export function getTypes(indices) {
}
// filter what we need
$.each(typeDict, function (type) {
ret.push(type);
});
if (Array.isArray(typeDict)) {
typeDict.forEach((type) => {
ret.push(type);
});
} else if (typeof typeDict === 'object') {
Object.keys(typeDict).forEach((type) => {
ret.push(type);
});
}
} else {
// multi index mode.
$.each(perIndexTypes, function (index) {
if (!indices || $.inArray(index, indices) !== -1) {
Object.keys(perIndexTypes).forEach((index) => {
if (!indices || indices.includes(index)) {
ret.push(getTypes(index));
}
});
@ -132,13 +139,15 @@ export function getTypes(indices) {
export function getIndices(includeAliases) {
const ret = [];
$.each(perIndexTypes, function (index) {
Object.keys(perIndexTypes).forEach((index) => {
// ignore .ds* indices in the suggested indices list.
if (!index.startsWith('.ds')) {
ret.push(index);
}
});
if (typeof includeAliases === 'undefined' ? true : includeAliases) {
$.each(perAliasIndexes, function (alias) {
Object.keys(perAliasIndexes).forEach((alias) => {
ret.push(alias);
});
}
@ -154,7 +163,7 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
function applyPathSettings(nestedFieldNames) {
const pathType = fieldMapping.path || 'full';
if (pathType === 'full') {
return $.map(nestedFieldNames, function (f) {
return nestedFieldNames.map((f) => {
f.name = fieldName + '.' + f.name;
return f;
});
@ -177,7 +186,7 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
}
if (fieldMapping.fields) {
nestedFields = $.map(fieldMapping.fields, function (fieldMapping, fieldName) {
nestedFields = Object.entries(fieldMapping.fields).flatMap(([fieldName, fieldMapping]) => {
return getFieldNamesFromFieldMapping(fieldName, fieldMapping);
});
nestedFields = applyPathSettings(nestedFields);
@ -189,7 +198,7 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
}
function getFieldNamesFromProperties(properties = {}) {
const fieldList = $.map(properties, function (fieldMapping, fieldName) {
const fieldList = Object.entries(properties).flatMap(([fieldName, fieldMapping]) => {
return getFieldNamesFromFieldMapping(fieldName, fieldMapping);
});
@ -218,15 +227,15 @@ export function loadDataStreams(data) {
export function loadMappings(mappings) {
perIndexTypes = {};
$.each(mappings, function (index, indexMapping) {
Object.entries(mappings).forEach(([index, indexMapping]) => {
const normalizedIndexMappings = {};
// Migrate 1.0.0 mappings. This format has changed, so we need to extract the underlying mapping.
if (indexMapping.mappings && _.keys(indexMapping).length === 1) {
if (indexMapping.mappings && Object.keys(indexMapping).length === 1) {
indexMapping = indexMapping.mappings;
}
$.each(indexMapping, function (typeName, typeMapping) {
Object.entries(indexMapping).forEach(([typeName, typeMapping]) => {
if (typeName === 'properties') {
const fieldList = getFieldNamesFromProperties(typeMapping);
normalizedIndexMappings[typeName] = fieldList;
@ -234,18 +243,17 @@ export function loadMappings(mappings) {
normalizedIndexMappings[typeName] = [];
}
});
perIndexTypes[index] = normalizedIndexMappings;
});
}
export function loadAliases(aliases) {
perAliasIndexes = {};
$.each(aliases || {}, function (index, omdexAliases) {
Object.entries(aliases).forEach(([index, omdexAliases]) => {
// verify we have an index defined. useful when mapping loading is disabled
perIndexTypes[index] = perIndexTypes[index] || {};
$.each(omdexAliases.aliases || {}, function (alias) {
Object.keys(omdexAliases.aliases || {}).forEach((alias) => {
if (alias === index) {
return;
} // alias which is identical to index means no index.
@ -269,7 +277,7 @@ export function clear() {
componentTemplates = [];
}
function retrieveSettings(settingsKey, settingsToRetrieve) {
function retrieveSettings(http, settingsKey, settingsToRetrieve) {
const settingKeyToPathMap = {
fields: '_mapping',
indices: '_aliases',
@ -278,22 +286,23 @@ function retrieveSettings(settingsKey, settingsToRetrieve) {
componentTemplates: '_component_template',
dataStreams: '_data_stream',
};
// Fetch autocomplete info if setting is set to true, and if user has made changes.
if (settingsToRetrieve[settingsKey] === true) {
// Use pretty=false in these request in order to compress the response by removing whitespace
const path = `${settingKeyToPathMap[settingsKey]}?pretty=false`;
const WITH_PRODUCT_ORIGIN = true;
const method = 'GET';
const asSystemRequest = true;
const withProductOrigin = true;
return es.send('GET', path, null, true, WITH_PRODUCT_ORIGIN);
return es.send({ http, method, path, asSystemRequest, withProductOrigin });
} else {
const settingsPromise = new $.Deferred();
if (settingsToRetrieve[settingsKey] === false) {
// If the user doesn't want autocomplete suggestions, then clear any that exist
return settingsPromise.resolveWith(this, [[JSON.stringify({})]]);
return Promise.resolve({});
// return settingsPromise.resolveWith(this, [{}]);
} else {
// If the user doesn't want autocomplete suggestions, then clear any that exist
return settingsPromise.resolve();
return Promise.resolve();
}
}
}
@ -315,12 +324,65 @@ export function clearSubscriptions() {
}
}
const retrieveMappings = async (http, settingsToRetrieve) => {
const mappings = await retrieveSettings(http, 'fields', settingsToRetrieve);
if (mappings) {
const maxMappingSize = Object.keys(mappings).length > 10 * 1024 * 1024;
let mappingsResponse;
if (maxMappingSize) {
console.warn(
`Mapping size is larger than 10MB (${
Object.keys(mappings).length / 1024 / 1024
} MB). Ignoring...`
);
mappingsResponse = '{}';
} else {
mappingsResponse = mappings;
}
loadMappings(mappingsResponse);
}
};
const retrieveAliases = async (http, settingsToRetrieve) => {
const aliases = await retrieveSettings(http, 'indices', settingsToRetrieve);
if (aliases) {
loadAliases(aliases);
}
};
const retrieveTemplates = async (http, settingsToRetrieve) => {
const legacyTemplates = await retrieveSettings(http, 'legacyTemplates', settingsToRetrieve);
const indexTemplates = await retrieveSettings(http, 'indexTemplates', settingsToRetrieve);
const componentTemplates = await retrieveSettings(http, 'componentTemplates', settingsToRetrieve);
if (legacyTemplates) {
loadLegacyTemplates(legacyTemplates);
}
if (indexTemplates) {
loadIndexTemplates(indexTemplates);
}
if (componentTemplates) {
loadComponentTemplates(componentTemplates);
}
};
const retrieveDataStreams = async (http, settingsToRetrieve) => {
const dataStreams = await retrieveSettings(http, 'dataStreams', settingsToRetrieve);
if (dataStreams) {
loadDataStreams(dataStreams);
}
};
/**
*
* @param settings Settings A way to retrieve the current settings
* @param settingsToRetrieve any
*/
export function retrieveAutoCompleteInfo(settings, settingsToRetrieve) {
export function retrieveAutoCompleteInfo(http, settings, settingsToRetrieve) {
clearSubscriptions();
const templatesSettingToRetrieve = {
@ -330,73 +392,18 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve) {
componentTemplates: settingsToRetrieve.templates,
};
const mappingPromise = retrieveSettings('fields', settingsToRetrieve);
const aliasesPromise = retrieveSettings('indices', settingsToRetrieve);
const legacyTemplatesPromise = retrieveSettings('legacyTemplates', templatesSettingToRetrieve);
const indexTemplatesPromise = retrieveSettings('indexTemplates', templatesSettingToRetrieve);
const componentTemplatesPromise = retrieveSettings(
'componentTemplates',
templatesSettingToRetrieve
);
const dataStreamsPromise = retrieveSettings('dataStreams', settingsToRetrieve);
$.when(
mappingPromise,
aliasesPromise,
legacyTemplatesPromise,
indexTemplatesPromise,
componentTemplatesPromise,
dataStreamsPromise
).done((mappings, aliases, legacyTemplates, indexTemplates, componentTemplates, dataStreams) => {
let mappingsResponse;
try {
if (mappings && mappings.length) {
const maxMappingSize = mappings[0].length > 10 * 1024 * 1024;
if (maxMappingSize) {
console.warn(
`Mapping size is larger than 10MB (${mappings[0].length / 1024 / 1024} MB). Ignoring...`
);
mappingsResponse = '[{}]';
} else {
mappingsResponse = mappings[0];
}
loadMappings(JSON.parse(mappingsResponse));
}
if (aliases) {
loadAliases(JSON.parse(aliases[0]));
}
if (legacyTemplates) {
loadLegacyTemplates(JSON.parse(legacyTemplates[0]));
}
if (indexTemplates) {
loadIndexTemplates(JSON.parse(indexTemplates[0]));
}
if (componentTemplates) {
loadComponentTemplates(JSON.parse(componentTemplates[0]));
}
if (dataStreams) {
loadDataStreams(JSON.parse(dataStreams[0]));
}
if (mappings && aliases) {
// Trigger an update event with the mappings, aliases
$(mappingObj).trigger('update', [mappingsResponse, aliases[0]]);
}
} catch (error) {
console.error(error);
}
Promise.allSettled([
retrieveMappings(http, settingsToRetrieve),
retrieveAliases(http, settingsToRetrieve),
retrieveTemplates(http, templatesSettingToRetrieve),
retrieveDataStreams(http, settingsToRetrieve),
]).then(() => {
// Schedule next request.
pollTimeoutId = setTimeout(() => {
// This looks strange/inefficient, but it ensures correct behavior because we don't want to send
// a scheduled request if the user turns off polling.
if (settings.getPolling()) {
retrieveAutoCompleteInfo(settings, settings.getAutocomplete());
retrieveAutoCompleteInfo(http, settings, settings.getAutocomplete());
}
}, settings.getPollInterval());
});

View file

@ -49,7 +49,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('default request response should include `"timed_out" : false`', async () => {
const expectedResponseContains = '"timed_out" : false,';
const expectedResponseContains = `"timed_out": false`;
await PageObjects.console.clickPlay();
await retry.try(async () => {
const actualResponse = await PageObjects.console.getResponse();