diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index c9ce825f3596e6..09881c00c63b6e 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -30,9 +30,16 @@ export function plugin() { export { DataStart }; export { Field, FieldType, IFieldList, IndexPattern } from './index_patterns'; -export { SavedQuery, SavedQueryTimeFilter } from '../../../../plugins/data/public'; +export { EsQuerySortValue, FetchOptions, ISearchSource, SortDirection } from './search/types'; +export { SearchSourceFields } from './search/types'; +export { + SavedQueryAttributes, + SavedQuery, + SavedQueryTimeFilter, +} from '../../../../plugins/data/public'; /** @public static code */ export * from '../common'; export { FilterStateManager } from './filter/filter_manager'; export { getFromSavedObject, getRoutes, flattenHitWrapper } from './index_patterns'; +export { getRequestInspectorStats, getResponseInspectorStats } from './search'; diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 676904faf6f2ff..6c67408158b51c 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,6 +18,7 @@ */ import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { SearchService, SearchStart } from './search'; import { DataPublicPluginStart } from '../../../../plugins/data/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -32,8 +33,9 @@ export interface DataPluginStartDependencies { * * @public */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface DataStart {} +export interface DataStart { + search: SearchStart; +} /** * Data Plugin - public @@ -48,13 +50,20 @@ export interface DataStart {} */ export class DataPlugin implements Plugin { + private readonly search = new SearchService(); + public setup(core: CoreSetup) {} public start(core: CoreStart, { data }: DataPluginStartDependencies): DataStart { // This is required for when Angular code uses Field and FieldList. setFieldFormats(data.fieldFormats); - return {}; + + return { + search: this.search.start(core), + }; } - public stop() {} + public stop() { + this.search.stop(); + } } diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index c94d35d1f7f2a5..a14e2c8492648f 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -32,7 +32,7 @@ import { import { npStart } from 'ui/new_platform'; import { SearchSource, - SearchSourceContract, + ISearchSource, getRequestInspectorStats, getResponseInspectorStats, } from '../../../../../ui/public/courier'; @@ -51,7 +51,7 @@ import { PersistedState } from '../../../../../ui/public/persisted_state'; import { Adapters } from '../../../../../../plugins/inspector/public'; export interface RequestHandlerParams { - searchSource: SearchSourceContract; + searchSource: ISearchSource; aggs: AggConfigs; timeRange?: TimeRange; query?: Query; diff --git a/src/legacy/ui/public/courier/fetch/call_client.test.ts b/src/legacy/core_plugins/data/public/search/fetch/call_client.test.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/call_client.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/call_client.test.ts diff --git a/src/legacy/ui/public/courier/fetch/call_client.ts b/src/legacy/core_plugins/data/public/search/fetch/call_client.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/call_client.ts rename to src/legacy/core_plugins/data/public/search/fetch/call_client.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_request.ts b/src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_request.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_request.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_request.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_response.ts b/src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_response.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_response.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_response.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap index 9a47fff2745c32..f7f3d1c1fbd0c2 100644 --- a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap +++ b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap @@ -181,7 +181,7 @@ exports[`ShardFailureModal renders matching snapshot given valid properties 1`] diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap diff --git a/src/legacy/ui/public/courier/fetch/components/_shard_failure_modal.scss b/src/legacy/core_plugins/data/public/search/fetch/components/_shard_failure_modal.scss similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/_shard_failure_modal.scss rename to src/legacy/core_plugins/data/public/search/fetch/components/_shard_failure_modal.scss diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx similarity index 96% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx index 6028a50cf9c3e4..60e0e35a0f1520 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { EuiCodeBlock, EuiDescriptionList, EuiSpacer } from '@elastic/eui'; import { ShardFailure } from './shard_failure_types'; -import { getFlattenedObject } from '../../../../../../legacy/utils/get_flattened_object'; +import { getFlattenedObject } from '../../../../../../../legacy/utils/get_flattened_object'; import { ShardFailureDescriptionHeader } from './shard_failure_description_header'; /** diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx similarity index 96% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx index ea4f33f9e914ef..947f33efa242c0 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx @@ -35,7 +35,7 @@ export function getFailureSummaryText(failure: ShardFailure, failureDetails?: st const displayDetails = typeof failureDetails === 'string' ? failureDetails : getFailureSummaryDetailsText(failure); - return i18n.translate('common.ui.courier.fetch.shardsFailedModal.failureHeader', { + return i18n.translate('data.search.searchSource.fetch.shardsFailedModal.failureHeader', { defaultMessage: '{failureName} at {failureDetails}', values: { failureName, failureDetails: displayDetails }, description: 'Summary of shard failures, e.g. "IllegalArgumentException at shard 0 node xyz"', diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_modal.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx similarity index 85% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx index d028a831a6e398..65cb49c6115756 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx @@ -59,15 +59,18 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) const tabs = [ { id: 'table', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures', { - defaultMessage: 'Shard failures', - description: 'Name of the tab displaying shard failures', - }), + name: i18n.translate( + 'data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures', + { + defaultMessage: 'Shard failures', + description: 'Name of the tab displaying shard failures', + } + ), content: , }, { id: 'json-request', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest', { defaultMessage: 'Request', description: 'Name of the tab displaying the JSON request', }), @@ -79,7 +82,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) }, { id: 'json-response', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse', { defaultMessage: 'Response', description: 'Name of the tab displaying the JSON response', }), @@ -104,7 +107,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) {copy => ( @@ -112,7 +115,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) onClose()} fill data-test-sub="closeShardFailureModal"> diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.mocks.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.mocks.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.mocks.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.mocks.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx similarity index 92% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx index b02344ce6dd728..d81ee70a4611cd 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx @@ -22,7 +22,7 @@ import { npStart } from 'ui/new_platform'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiTextAlign } from '@elastic/eui'; -import { toMountPoint } from '../../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../plugins/kibana_react/public'; import { ShardFailureModal } from './shard_failure_modal'; import { ResponseWithShardFailure, Request } from './shard_failure_types'; @@ -57,7 +57,7 @@ export function ShardFailureOpenModalButton({ request, response, title }: Props) data-test-subj="openShardFailureModalBtn" > diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_table.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx similarity index 87% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx index 54de64e52f745e..5d5047631231ab 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx @@ -44,7 +44,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { render: (item: ListItem) => { const failureSummeryText = getFailureSummaryText(item); const collapseLabel = i18n.translate( - 'common.ui.courier.fetch.shardsFailedModal.tableRowCollapse', + 'data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse', { defaultMessage: 'Collapse {rowDescription}', description: 'Collapse a row of a table with failures', @@ -53,7 +53,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { ); const expandLabel = i18n.translate( - 'common.ui.courier.fetch.shardsFailedModal.tableRowExpand', + 'data.search.searchSource.fetch.shardsFailedModal.tableRowExpand', { defaultMessage: 'Expand {rowDescription}', description: 'Expand a row of a table with failures', @@ -81,7 +81,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'shard', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColShard', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColShard', { defaultMessage: 'Shard', }), sortable: true, @@ -90,7 +90,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'index', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColIndex', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColIndex', { defaultMessage: 'Index', }), sortable: true, @@ -98,7 +98,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'node', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColNode', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColNode', { defaultMessage: 'Node', }), sortable: true, @@ -106,7 +106,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'reason.type', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColReason', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColReason', { defaultMessage: 'Reason', }), truncateText: true, diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_types.ts b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_types.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_types.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_types.ts diff --git a/src/legacy/ui/public/courier/fetch/errors.ts b/src/legacy/core_plugins/data/public/search/fetch/errors.ts similarity index 91% rename from src/legacy/ui/public/courier/fetch/errors.ts rename to src/legacy/core_plugins/data/public/search/fetch/errors.ts index a2ac013915b4bb..5f5dc0452df513 100644 --- a/src/legacy/ui/public/courier/fetch/errors.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/errors.ts @@ -17,9 +17,10 @@ * under the License. */ -import { SearchError } from '../../courier'; -import { KbnError } from '../../../../../plugins/kibana_utils/public'; +import { SearchError } from '../search_strategy'; +import { KbnError } from '../../../../../../plugins/kibana_utils/public'; import { SearchResponse } from '../types'; + /** * Request Failure - When an entire multi request fails * @param {Error} err - the Error that came back diff --git a/src/legacy/ui/public/courier/fetch/fetch_soon.test.ts b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts similarity index 98% rename from src/legacy/ui/public/courier/fetch/fetch_soon.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts index d96fb536985da0..69a343c78b1e12 100644 --- a/src/legacy/ui/public/courier/fetch/fetch_soon.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts @@ -19,7 +19,7 @@ import { fetchSoon } from './fetch_soon'; import { callClient } from './call_client'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { FetchHandlers, FetchOptions } from './types'; import { SearchRequest, SearchResponse } from '../types'; diff --git a/src/legacy/ui/public/courier/fetch/fetch_soon.ts b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/fetch_soon.ts rename to src/legacy/core_plugins/data/public/search/fetch/fetch_soon.ts diff --git a/src/legacy/ui/public/courier/fetch/get_search_params.test.ts b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts similarity index 98% rename from src/legacy/ui/public/courier/fetch/get_search_params.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts index 76f3105d7f942e..f856aa77bf1f8e 100644 --- a/src/legacy/ui/public/courier/fetch/get_search_params.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts @@ -18,7 +18,7 @@ */ import { getMSearchParams, getSearchParams } from './get_search_params'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; function getConfigStub(config: any = {}) { return { diff --git a/src/legacy/ui/public/courier/fetch/get_search_params.ts b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts similarity index 97% rename from src/legacy/ui/public/courier/fetch/get_search_params.ts rename to src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts index 9fb8f2c728c6f0..de9ec4cb920e8e 100644 --- a/src/legacy/ui/public/courier/fetch/get_search_params.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; const sessionId = Date.now(); diff --git a/src/legacy/ui/public/courier/fetch/handle_response.test.ts b/src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts similarity index 95% rename from src/legacy/ui/public/courier/fetch/handle_response.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts index 0163aca7771610..f8763a71d840e4 100644 --- a/src/legacy/ui/public/courier/fetch/handle_response.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts @@ -18,9 +18,9 @@ */ import { handleResponse } from './handle_response'; -import { toastNotifications } from '../../notify/toasts'; +import { toastNotifications } from 'ui/notify/toasts'; -jest.mock('../../notify/toasts', () => { +jest.mock('ui/notify/toasts', () => { return { toastNotifications: { addWarning: jest.fn(), diff --git a/src/legacy/ui/public/courier/fetch/handle_response.tsx b/src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx similarity index 84% rename from src/legacy/ui/public/courier/fetch/handle_response.tsx rename to src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx index d7f2263268f8c4..e3fd5ad15242d0 100644 --- a/src/legacy/ui/public/courier/fetch/handle_response.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx @@ -20,23 +20,23 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSpacer } from '@elastic/eui'; -import { toastNotifications } from '../../notify/toasts'; +import { toastNotifications } from 'ui/notify/toasts'; import { ShardFailureOpenModalButton } from './components/shard_failure_open_modal_button'; import { Request, ResponseWithShardFailure } from './components/shard_failure_types'; import { SearchRequest, SearchResponse } from '../types'; -import { toMountPoint } from '../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../plugins/kibana_react/public'; export function handleResponse(request: SearchRequest, response: SearchResponse) { if (response.timed_out) { toastNotifications.addWarning({ - title: i18n.translate('common.ui.courier.fetch.requestTimedOutNotificationMessage', { + title: i18n.translate('data.search.searchSource.fetch.requestTimedOutNotificationMessage', { defaultMessage: 'Data might be incomplete because your request timed out', }), }); } if (response._shards && response._shards.failed) { - const title = i18n.translate('common.ui.courier.fetch.shardsFailedNotificationMessage', { + const title = i18n.translate('data.search.searchSource.fetch.shardsFailedNotificationMessage', { defaultMessage: '{shardsFailed} of {shardsTotal} shards failed', values: { shardsFailed: response._shards.failed, @@ -44,7 +44,7 @@ export function handleResponse(request: SearchRequest, response: SearchResponse) }, }); const description = i18n.translate( - 'common.ui.courier.fetch.shardsFailedNotificationDescription', + 'data.search.searchSource.fetch.shardsFailedNotificationDescription', { defaultMessage: 'The data you are seeing might be incomplete or wrong.', } diff --git a/src/legacy/ui/public/courier/fetch/index.ts b/src/legacy/core_plugins/data/public/search/fetch/index.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/index.ts rename to src/legacy/core_plugins/data/public/search/fetch/index.ts diff --git a/src/legacy/ui/public/courier/fetch/types.ts b/src/legacy/core_plugins/data/public/search/fetch/types.ts similarity index 95% rename from src/legacy/ui/public/courier/fetch/types.ts rename to src/legacy/core_plugins/data/public/search/fetch/types.ts index 03bf51ae15d453..0887a1f84c7c8c 100644 --- a/src/legacy/ui/public/courier/fetch/types.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { SearchRequest, SearchResponse } from '../types'; export interface ApiCaller { diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts index 9880b336e76e5c..d930a472195147 100644 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ b/src/legacy/core_plugins/data/public/search/index.ts @@ -16,3 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + +export { SearchService, SearchSetup, SearchStart } from './search_service'; + +export { getRequestInspectorStats, getResponseInspectorStats } from './utils'; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts new file mode 100644 index 00000000000000..85701187fb31d8 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -0,0 +1,51 @@ +/* + * 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 { Plugin, CoreSetup, CoreStart } from '../../../../../core/public'; +import { SearchSource } from './search_source'; +import { defaultSearchStrategy } from './search_strategy'; +import { SearchStrategyProvider } from './search_strategy/types'; + +export interface SearchSetup {} // eslint-disable-line @typescript-eslint/no-empty-interface + +export interface SearchStart { + defaultSearchStrategy: SearchStrategyProvider; + SearchSource: typeof SearchSource; +} + +/** + * The contract provided here is a new platform shim for ui/courier. + * + * Once it has been refactored to work with new platform services, + * it will move into the existing search service in src/plugins/data/public/search + */ +export class SearchService implements Plugin { + public setup(core: CoreSetup): SearchSetup { + return {}; + } + + public start(core: CoreStart): SearchStart { + return { + defaultSearchStrategy, + SearchSource, + }; + } + + public stop() {} +} diff --git a/src/legacy/ui/public/courier/search_source/filter_docvalue_fields.test.ts b/src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.test.ts similarity index 100% rename from src/legacy/ui/public/courier/search_source/filter_docvalue_fields.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.test.ts diff --git a/src/legacy/ui/public/courier/search_source/filter_docvalue_fields.ts b/src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.ts similarity index 100% rename from src/legacy/ui/public/courier/search_source/filter_docvalue_fields.ts rename to src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.ts diff --git a/src/legacy/core_plugins/data/public/search/search_source/index.ts b/src/legacy/core_plugins/data/public/search/search_source/index.ts new file mode 100644 index 00000000000000..72170adc2b1296 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './search_source'; diff --git a/src/legacy/core_plugins/data/public/search/search_source/mocks.ts b/src/legacy/core_plugins/data/public/search/search_source/mocks.ts new file mode 100644 index 00000000000000..fd72158012de6f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/mocks.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/* + * 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 { ISearchSource } from './search_source'; + +export const searchSourceMock: MockedKeys = { + setPreferredSearchStrategyId: jest.fn(), + setFields: jest.fn().mockReturnThis(), + setField: jest.fn().mockReturnThis(), + getId: jest.fn(), + getFields: jest.fn(), + getField: jest.fn(), + getOwnField: jest.fn(), + create: jest.fn().mockReturnThis(), + createCopy: jest.fn().mockReturnThis(), + createChild: jest.fn().mockReturnThis(), + setParent: jest.fn(), + getParent: jest.fn().mockReturnThis(), + fetch: jest.fn().mockResolvedValue({}), + onRequestStart: jest.fn(), + getSearchRequestBody: jest.fn(), + destroy: jest.fn(), + history: [], +}; diff --git a/src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts similarity index 97% rename from src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts index d27b01eb5cf7cf..22d1d931a9d096 100644 --- a/src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts @@ -19,7 +19,7 @@ import { normalizeSortRequest } from './normalize_sort_request'; import { SortDirection } from './types'; -import { IndexPattern } from '../../../../core_plugins/data/public/index_patterns'; +import { IIndexPattern } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -40,7 +40,7 @@ describe('SearchSource#normalizeSortRequest', function() { }; const indexPattern = { fields: [scriptedField, murmurScriptedField], - } as IndexPattern; + } as IIndexPattern; it('should return an array', function() { const sortable = { someField: SortDirection.desc }; diff --git a/src/legacy/ui/public/courier/search_source/normalize_sort_request.ts b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts similarity index 93% rename from src/legacy/ui/public/courier/search_source/normalize_sort_request.ts rename to src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts index 0f8fc8076caa08..93834c95514dc2 100644 --- a/src/legacy/ui/public/courier/search_source/normalize_sort_request.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts @@ -17,12 +17,12 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IIndexPattern } from '../../../../../../plugins/data/public'; import { EsQuerySortValue, SortOptions } from './types'; export function normalizeSortRequest( sortObject: EsQuerySortValue | EsQuerySortValue[], - indexPattern: IndexPattern | string | undefined, + indexPattern: IIndexPattern | string | undefined, defaultSortOptions: SortOptions = {} ) { const sortArray: EsQuerySortValue[] = Array.isArray(sortObject) ? sortObject : [sortObject]; @@ -38,7 +38,7 @@ export function normalizeSortRequest( */ function normalize( sortable: EsQuerySortValue, - indexPattern: IndexPattern | string | undefined, + indexPattern: IIndexPattern | string | undefined, defaultSortOptions: any ) { const [[sortField, sortOrder]] = Object.entries(sortable); diff --git a/src/legacy/ui/public/courier/search_source/search_source.test.ts b/src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_source/search_source.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts index ddd3717f55e297..28f8dba9a75de3 100644 --- a/src/legacy/ui/public/courier/search_source/search_source.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts @@ -18,7 +18,7 @@ */ import { SearchSource } from '../search_source'; -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -26,7 +26,7 @@ jest.mock('../fetch', () => ({ fetchSoon: jest.fn().mockResolvedValue({}), })); -jest.mock('../../chrome', () => ({ +jest.mock('ui/chrome', () => ({ dangerouslyGetActiveInjector: () => ({ get: jest.fn(), }), diff --git a/src/legacy/core_plugins/data/public/search/search_source/search_source.ts b/src/legacy/core_plugins/data/public/search/search_source/search_source.ts new file mode 100644 index 00000000000000..01fc34e230a316 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/search_source.ts @@ -0,0 +1,410 @@ +/* + * 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. + */ + +/** + * @name SearchSource + * + * @description A promise-based stream of search results that can inherit from other search sources. + * + * Because filters/queries in Kibana have different levels of persistence and come from different + * places, it is important to keep track of where filters come from for when they are saved back to + * the savedObject store in the Kibana index. To do this, we create trees of searchSource objects + * that can have associated query parameters (index, query, filter, etc) which can also inherit from + * other searchSource objects. + * + * At query time, all of the searchSource objects that have subscribers are "flattened", at which + * point the query params from the searchSource are collected while traversing up the inheritance + * chain. At each link in the chain a decision about how to merge the query params is made until a + * single set of query parameters is created for each active searchSource (a searchSource with + * subscribers). + * + * That set of query parameters is then sent to elasticsearch. This is how the filter hierarchy + * works in Kibana. + * + * Visualize, starting from a new search: + * + * - the `savedVis.searchSource` is set as the `appSearchSource`. + * - The `savedVis.searchSource` would normally inherit from the `appSearchSource`, but now it is + * upgraded to inherit from the `rootSearchSource`. + * - Any interaction with the visualization will still apply filters to the `appSearchSource`, so + * they will be stored directly on the `savedVis.searchSource`. + * - Any interaction with the time filter will be written to the `rootSearchSource`, so those + * filters will not be saved by the `savedVis`. + * - When the `savedVis` is saved to elasticsearch, it takes with it all the filters that are + * defined on it directly, but none of the ones that it inherits from other places. + * + * Visualize, starting from an existing search: + * + * - The `savedVis` loads the `savedSearch` on which it is built. + * - The `savedVis.searchSource` is set to inherit from the `saveSearch.searchSource` and set as + * the `appSearchSource`. + * - The `savedSearch.searchSource`, is set to inherit from the `rootSearchSource`. + * - Then the `savedVis` is written to elasticsearch it will be flattened and only include the + * filters created in the visualize application and will reconnect the filters from the + * `savedSearch` at runtime to prevent losing the relationship + * + * Dashboard search sources: + * + * - Each panel in a dashboard has a search source. + * - The `savedDashboard` also has a searchsource, and it is set as the `appSearchSource`. + * - Each panel's search source inherits from the `appSearchSource`, meaning that they inherit from + * the dashboard search source. + * - When a filter is added to the search box, or via a visualization, it is written to the + * `appSearchSource`. + */ + +import _ from 'lodash'; +import { npSetup } from 'ui/new_platform'; +import chrome from 'ui/chrome'; +import { fieldWildcardFilter } from 'ui/field_wildcard'; +import { normalizeSortRequest } from './normalize_sort_request'; +import { fetchSoon } from '../fetch'; +import { getHighlightRequest, esFilters, esQuery } from '../../../../../../plugins/data/public'; +import { RequestFailure } from '../fetch/errors'; +import { filterDocvalueFields } from './filter_docvalue_fields'; +import { SearchSourceOptions, SearchSourceFields, SearchRequest } from './types'; +import { FetchOptions, ApiCaller } from '../fetch/types'; + +const esShardTimeout = npSetup.core.injectedMetadata.getInjectedVar('esShardTimeout') as number; +const config = npSetup.core.uiSettings; + +export type ISearchSource = Pick; + +export class SearchSource { + private id: string = _.uniqueId('data_source'); + private searchStrategyId?: string; + private parent?: SearchSource; + private requestStartHandlers: Array< + (searchSource: ISearchSource, options?: FetchOptions) => Promise + > = []; + private inheritOptions: SearchSourceOptions = {}; + public history: SearchRequest[] = []; + + constructor(private fields: SearchSourceFields = {}) {} + + /** *** + * PUBLIC API + *****/ + + setPreferredSearchStrategyId(searchStrategyId: string) { + this.searchStrategyId = searchStrategyId; + } + + setFields(newFields: SearchSourceFields) { + this.fields = newFields; + return this; + } + + setField(field: K, value: SearchSourceFields[K]) { + if (value == null) { + delete this.fields[field]; + } else { + this.fields[field] = value; + } + return this; + } + + getId() { + return this.id; + } + + getFields() { + return { ...this.fields }; + } + + /** + * Get fields from the fields + */ + getField(field: K, recurse = true): SearchSourceFields[K] { + if (!recurse || this.fields[field] !== void 0) { + return this.fields[field]; + } + const parent = this.getParent(); + return parent && parent.getField(field); + } + + /** + * Get the field from our own fields, don't traverse up the chain + */ + getOwnField(field: K): SearchSourceFields[K] { + return this.getField(field, false); + } + + create() { + return new SearchSource(); + } + + createCopy() { + const newSearchSource = new SearchSource(); + newSearchSource.setFields({ ...this.fields }); + // when serializing the internal fields we lose the internal classes used in the index + // pattern, so we have to set it again to workaround this behavior + newSearchSource.setField('index', this.getField('index')); + newSearchSource.setParent(this.getParent()); + return newSearchSource; + } + + createChild(options = {}) { + const childSearchSource = new SearchSource(); + childSearchSource.setParent(this, options); + return childSearchSource; + } + + /** + * Set a searchSource that this source should inherit from + * @param {SearchSource} parent - the parent searchSource + * @param {SearchSourceOptions} options - the inherit options + * @return {this} - chainable + */ + setParent(parent?: ISearchSource, options: SearchSourceOptions = {}) { + this.parent = parent as SearchSource; + this.inheritOptions = options; + return this; + } + + /** + * Get the parent of this SearchSource + * @return {undefined|searchSource} + */ + getParent() { + return this.parent; + } + + /** + * Fetch this source and reject the returned Promise on error + * + * @async + */ + async fetch(options: FetchOptions = {}) { + const $injector = await chrome.dangerouslyGetActiveInjector(); + const es = $injector.get('es') as ApiCaller; + + await this.requestIsStarting(options); + + const searchRequest = await this.flatten(); + this.history = [searchRequest]; + + const response = await fetchSoon( + searchRequest, + { + ...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }), + ...options, + }, + { es, config, esShardTimeout } + ); + + if (response.error) { + throw new RequestFailure(null, response); + } + + return response; + } + + /** + * Add a handler that will be notified whenever requests start + * @param {Function} handler + * @return {undefined} + */ + onRequestStart( + handler: (searchSource: ISearchSource, options?: FetchOptions) => Promise + ) { + this.requestStartHandlers.push(handler); + } + + async getSearchRequestBody() { + const searchRequest = await this.flatten(); + return searchRequest.body; + } + + /** + * Completely destroy the SearchSource. + * @return {undefined} + */ + destroy() { + this.requestStartHandlers.length = 0; + } + + /** **** + * PRIVATE APIS + ******/ + + /** + * Called by requests of this search source when they are started + * @param {Courier.Request} request + * @param options + * @return {Promise} + */ + private requestIsStarting(options: FetchOptions = {}) { + const handlers = [...this.requestStartHandlers]; + // If callParentStartHandlers has been set to true, we also call all + // handlers of parent search sources. + if (this.inheritOptions.callParentStartHandlers) { + let searchSource = this.getParent(); + while (searchSource) { + handlers.push(...searchSource.requestStartHandlers); + searchSource = searchSource.getParent(); + } + } + + return Promise.all(handlers.map(fn => fn(this, options))); + } + + /** + * Used to merge properties into the data within ._flatten(). + * The data is passed in and modified by the function + * + * @param {object} data - the current merged data + * @param {*} val - the value at `key` + * @param {*} key - The key of `val` + * @return {undefined} + */ + private mergeProp( + data: SearchRequest, + val: SearchSourceFields[K], + key: K + ) { + val = typeof val === 'function' ? val(this) : val; + if (val == null || !key) return; + + const addToRoot = (rootKey: string, value: any) => { + data[rootKey] = value; + }; + + /** + * Add the key and val to the body of the request + */ + const addToBody = (bodyKey: string, value: any) => { + // ignore if we already have a value + if (data.body[bodyKey] == null) { + data.body[bodyKey] = value; + } + }; + + switch (key) { + case 'filter': + return addToRoot('filters', (data.filters || []).concat(val)); + case 'query': + return addToRoot(key, (data[key] || []).concat(val)); + case 'fields': + const fields = _.uniq((data[key] || []).concat(val)); + return addToRoot(key, fields); + case 'index': + case 'type': + case 'highlightAll': + return key && data[key] == null && addToRoot(key, val); + case 'searchAfter': + return addToBody('search_after', val); + case 'source': + return addToBody('_source', val); + case 'sort': + const sort = normalizeSortRequest(val, this.getField('index'), config.get('sort:options')); + return addToBody(key, sort); + default: + return addToBody(key, val); + } + } + + /** + * Walk the inheritance chain of a source and return its + * flat representation (taking into account merging rules) + * @returns {Promise} + * @resolved {Object|null} - the flat data of the SearchSource + */ + private mergeProps(root = this, searchRequest: SearchRequest = { body: {} }) { + Object.entries(this.fields).forEach(([key, value]) => { + this.mergeProp(searchRequest, value, key as keyof SearchSourceFields); + }); + if (this.parent) { + this.parent.mergeProps(root, searchRequest); + } + return searchRequest; + } + + private flatten() { + const searchRequest = this.mergeProps(); + + searchRequest.body = searchRequest.body || {}; + const { body, index, fields, query, filters, highlightAll } = searchRequest; + + const computedFields = index ? index.getComputedFields() : {}; + + body.stored_fields = computedFields.storedFields; + body.script_fields = body.script_fields || {}; + _.extend(body.script_fields, computedFields.scriptFields); + + const defaultDocValueFields = computedFields.docvalueFields + ? computedFields.docvalueFields + : []; + body.docvalue_fields = body.docvalue_fields || defaultDocValueFields; + + if (!body.hasOwnProperty('_source') && index) { + body._source = index.getSourceFiltering(); + } + + if (body._source) { + // exclude source fields for this index pattern specified by the user + const filter = fieldWildcardFilter(body._source.excludes, config.get('metaFields')); + body.docvalue_fields = body.docvalue_fields.filter((docvalueField: any) => + filter(docvalueField.field) + ); + } + + // if we only want to search for certain fields + if (fields) { + // filter out the docvalue_fields, and script_fields to only include those that we are concerned with + body.docvalue_fields = filterDocvalueFields(body.docvalue_fields, fields); + body.script_fields = _.pick(body.script_fields, fields); + + // request the remaining fields from both stored_fields and _source + const remainingFields = _.difference(fields, _.keys(body.script_fields)); + body.stored_fields = remainingFields; + _.set(body, '_source.includes', remainingFields); + } + + const esQueryConfigs = esQuery.getEsQueryConfig(config); + body.query = esQuery.buildEsQuery(index, query, filters, esQueryConfigs); + + if (highlightAll && body.query) { + body.highlight = getHighlightRequest(body.query, config.get('doc_table:highlight')); + delete searchRequest.highlightAll; + } + + const translateToQuery = (filter: esFilters.Filter) => filter && (filter.query || filter); + + // re-write filters within filter aggregations + (function recurse(aggBranch) { + if (!aggBranch) return; + Object.keys(aggBranch).forEach(function(id) { + const agg = aggBranch[id]; + + if (agg.filters) { + // translate filters aggregations + const { filters: aggFilters } = agg.filters; + Object.keys(aggFilters).forEach(filterId => { + aggFilters[filterId] = translateToQuery(aggFilters[filterId]); + }); + } + + recurse(agg.aggs || agg.aggregations); + }); + })(body.aggs || body.aggregations); + + return searchRequest; + } +} diff --git a/src/legacy/ui/public/courier/search_source/types.ts b/src/legacy/core_plugins/data/public/search/search_source/types.ts similarity index 94% rename from src/legacy/ui/public/courier/search_source/types.ts rename to src/legacy/core_plugins/data/public/search/search_source/types.ts index 8fd6d8cfa5fa09..9c5b57519d75f9 100644 --- a/src/legacy/ui/public/courier/search_source/types.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/types.ts @@ -17,7 +17,7 @@ * under the License. */ import { NameList } from 'elasticsearch'; -import { esFilters, Query, IndexPattern } from '../../../../../plugins/data/public'; +import { esFilters, IndexPattern, Query } from '../../../../../../plugins/data/public'; export type EsQuerySearchAfter = [string | number, string | number]; @@ -54,7 +54,7 @@ export interface SearchSourceOptions { callParentStartHandlers?: boolean; } -export { SearchSourceContract } from './search_source'; +export { ISearchSource } from './search_source'; export interface SortOptions { mode?: 'min' | 'max' | 'sum' | 'avg' | 'median'; diff --git a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts index 53a857a72c1a3a..0ec6a6c2e143e7 100644 --- a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts @@ -18,7 +18,7 @@ */ import { defaultSearchStrategy } from './default_search_strategy'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { SearchStrategySearchParams } from './types'; const { search } = defaultSearchStrategy; diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts new file mode 100644 index 00000000000000..9bfa1df71aa81a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts @@ -0,0 +1,78 @@ +/* + * 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 { SearchStrategyProvider, SearchStrategySearchParams } from './types'; +import { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; +import { + getSearchParams, + getMSearchParams, + getPreference, + getTimeout, +} from '../fetch/get_search_params'; + +export const defaultSearchStrategy: SearchStrategyProvider = { + id: 'default', + + search: params => { + return params.config.get('courier:batchSearches') ? msearch(params) : search(params); + }, + + isViable: indexPattern => { + return indexPattern && isDefaultTypeIndexPattern(indexPattern); + }, +}; + +function msearch({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { + const inlineRequests = searchRequests.map(({ index, body, search_type: searchType }) => { + const inlineHeader = { + index: index.title || index, + search_type: searchType, + ignore_unavailable: true, + preference: getPreference(config), + }; + const inlineBody = { + ...body, + timeout: getTimeout(esShardTimeout), + }; + return `${JSON.stringify(inlineHeader)}\n${JSON.stringify(inlineBody)}`; + }); + + const searching = es.msearch({ + ...getMSearchParams(config), + body: `${inlineRequests.join('\n')}\n`, + }); + return { + searching: searching.then(({ responses }) => responses), + abort: searching.abort, + }; +} + +function search({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { + const abortController = new AbortController(); + const searchParams = getSearchParams(config, esShardTimeout); + const promises = searchRequests.map(({ index, body }) => { + const searching = es.search({ index: index.title || index, body, ...searchParams }); + abortController.signal.addEventListener('abort', searching.abort); + return searching.catch(({ response }) => JSON.parse(response)); + }); + return { + searching: Promise.all(promises), + abort: () => abortController.abort(), + }; +} diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/index.ts b/src/legacy/core_plugins/data/public/search/search_strategy/index.ts new file mode 100644 index 00000000000000..1584baa4faade4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/index.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +export { + addSearchStrategy, + hasSearchStategyForIndexPattern, + getSearchStrategyById, + getSearchStrategyForSearchRequest, +} from './search_strategy_registry'; + +export { defaultSearchStrategy } from './default_search_strategy'; + +export { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; + +export { SearchError, getSearchErrorType } from './search_error'; diff --git a/src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts b/src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts similarity index 93% rename from src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts index 3785ce63410787..7d03b1dc9e0b1a 100644 --- a/src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; export const isDefaultTypeIndexPattern = (indexPattern: IndexPattern) => { // Default index patterns don't have `type` defined. diff --git a/src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts b/src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts similarity index 83% rename from src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts index 24c3876cfcc051..dc7331e614a0e4 100644 --- a/src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts @@ -27,11 +27,14 @@ export const noOpSearchStrategy: SearchStrategyProvider = { search: () => { const searchError = new SearchError({ status: '418', // "I'm a teapot" error - title: i18n.translate('common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle', { - defaultMessage: 'No search strategy registered', - }), + title: i18n.translate( + 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle', + { + defaultMessage: 'No search strategy registered', + } + ), message: i18n.translate( - 'common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription', + 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription', { defaultMessage: `Couldn't find a search strategy for the search request`, } diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts new file mode 100644 index 00000000000000..d4042fb17499cb --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ + +interface SearchErrorOptions { + status: string; + title: string; + message: string; + path: string; + type: string; +} + +export class SearchError extends Error { + public name: string; + public status: string; + public title: string; + public message: string; + public path: string; + public type: string; + + constructor({ status, title, message, path, type }: SearchErrorOptions) { + super(message); + this.name = 'SearchError'; + this.status = status; + this.title = title; + this.message = message; + this.path = path; + this.type = type; + + // captureStackTrace is only available in the V8 engine, so any browser using + // a different JS engine won't have access to this method. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, SearchError); + } + + // Babel doesn't support traditional `extends` syntax for built-in classes. + // https://babeljs.io/docs/en/caveats/#classes + Object.setPrototypeOf(this, SearchError.prototype); + } +} + +export function getSearchErrorType({ message }: Pick) { + const msg = message.toLowerCase(); + if (msg.indexOf('unsupported query') > -1) { + return 'UNSUPPORTED_QUERY'; + } +} diff --git a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts index ae2ed6128c8ea8..73b011896a97dc 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { noOpSearchStrategy } from './no_op_search_strategy'; import { searchStrategies, diff --git a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts similarity index 97% rename from src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts index 9ef007f97531ea..d814a04737f753 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { SearchStrategyProvider } from './types'; import { noOpSearchStrategy } from './no_op_search_strategy'; import { SearchResponse } from '../types'; diff --git a/src/legacy/ui/public/courier/search_strategy/types.ts b/src/legacy/core_plugins/data/public/search/search_strategy/types.ts similarity index 94% rename from src/legacy/ui/public/courier/search_strategy/types.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/types.ts index 1542f9824a5b1b..ad8576589e4e38 100644 --- a/src/legacy/ui/public/courier/search_strategy/types.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { FetchHandlers } from '../fetch/types'; import { SearchRequest, SearchResponse } from '../types'; diff --git a/src/legacy/core_plugins/data/public/search/types.ts b/src/legacy/core_plugins/data/public/search/types.ts new file mode 100644 index 00000000000000..23d74ce6a57da8 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/types.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export * from './fetch/types'; +export * from './search_source/types'; +export * from './search_strategy/types'; +export * from './utils/types'; diff --git a/src/legacy/ui/public/courier/utils/courier_inspector_utils.ts b/src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts similarity index 72% rename from src/legacy/ui/public/courier/utils/courier_inspector_utils.ts rename to src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts index b4d5d5537333e3..7f7d216d8f0f3f 100644 --- a/src/legacy/ui/public/courier/utils/courier_inspector_utils.ts +++ b/src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts @@ -26,28 +26,28 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; -import { SearchSourceContract, RequestInspectorStats } from '../types'; +import { ISearchSource, RequestInspectorStats } from '../types'; -export function getRequestInspectorStats(searchSource: SearchSourceContract) { +export function getRequestInspectorStats(searchSource: ISearchSource) { const stats: RequestInspectorStats = {}; const index = searchSource.getField('index'); if (index) { stats.indexPattern = { - label: i18n.translate('common.ui.courier.indexPatternLabel', { + label: i18n.translate('data.search.searchSource.indexPatternLabel', { defaultMessage: 'Index pattern', }), value: index.title, - description: i18n.translate('common.ui.courier.indexPatternDescription', { + description: i18n.translate('data.search.searchSource.indexPatternDescription', { defaultMessage: 'The index pattern that connected to the Elasticsearch indices.', }), }; stats.indexPatternId = { - label: i18n.translate('common.ui.courier.indexPatternIdLabel', { + label: i18n.translate('data.search.searchSource.indexPatternIdLabel', { defaultMessage: 'Index pattern ID', }), value: index.id!, - description: i18n.translate('common.ui.courier.indexPatternIdDescription', { + description: i18n.translate('data.search.searchSource.indexPatternIdDescription', { defaultMessage: 'The ID in the {kibanaIndexPattern} index.', values: { kibanaIndexPattern: '.kibana' }, }), @@ -58,7 +58,7 @@ export function getRequestInspectorStats(searchSource: SearchSourceContract) { } export function getResponseInspectorStats( - searchSource: SearchSourceContract, + searchSource: ISearchSource, resp: SearchResponse ) { const lastRequest = searchSource.history && searchSource.history[searchSource.history.length - 1]; @@ -66,14 +66,14 @@ export function getResponseInspectorStats( if (resp && resp.took) { stats.queryTime = { - label: i18n.translate('common.ui.courier.queryTimeLabel', { + label: i18n.translate('data.search.searchSource.queryTimeLabel', { defaultMessage: 'Query time', }), - value: i18n.translate('common.ui.courier.queryTimeValue', { + value: i18n.translate('data.search.searchSource.queryTimeValue', { defaultMessage: '{queryTime}ms', values: { queryTime: resp.took }, }), - description: i18n.translate('common.ui.courier.queryTimeDescription', { + description: i18n.translate('data.search.searchSource.queryTimeDescription', { defaultMessage: 'The time it took to process the query. ' + 'Does not include the time to send the request or parse it in the browser.', @@ -83,21 +83,21 @@ export function getResponseInspectorStats( if (resp && resp.hits) { stats.hitsTotal = { - label: i18n.translate('common.ui.courier.hitsTotalLabel', { + label: i18n.translate('data.search.searchSource.hitsTotalLabel', { defaultMessage: 'Hits (total)', }), value: `${resp.hits.total}`, - description: i18n.translate('common.ui.courier.hitsTotalDescription', { + description: i18n.translate('data.search.searchSource.hitsTotalDescription', { defaultMessage: 'The number of documents that match the query.', }), }; stats.hits = { - label: i18n.translate('common.ui.courier.hitsLabel', { + label: i18n.translate('data.search.searchSource.hitsLabel', { defaultMessage: 'Hits', }), value: `${resp.hits.hits.length}`, - description: i18n.translate('common.ui.courier.hitsDescription', { + description: i18n.translate('data.search.searchSource.hitsDescription', { defaultMessage: 'The number of documents returned by the query.', }), }; @@ -105,14 +105,14 @@ export function getResponseInspectorStats( if (lastRequest && (lastRequest.ms === 0 || lastRequest.ms)) { stats.requestTime = { - label: i18n.translate('common.ui.courier.requestTimeLabel', { + label: i18n.translate('data.search.searchSource.requestTimeLabel', { defaultMessage: 'Request time', }), - value: i18n.translate('common.ui.courier.requestTimeValue', { + value: i18n.translate('data.search.searchSource.requestTimeValue', { defaultMessage: '{requestTime}ms', values: { requestTime: lastRequest.ms }, }), - description: i18n.translate('common.ui.courier.requestTimeDescription', { + description: i18n.translate('data.search.searchSource.requestTimeDescription', { defaultMessage: 'The time of the request from the browser to Elasticsearch and back. ' + 'Does not include the time the requested waited in the queue.', diff --git a/src/legacy/core_plugins/data/public/search/utils/index.ts b/src/legacy/core_plugins/data/public/search/utils/index.ts new file mode 100644 index 00000000000000..021ece8701e981 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/utils/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './courier_inspector_utils'; diff --git a/src/legacy/ui/public/courier/utils/types.ts b/src/legacy/core_plugins/data/public/search/utils/types.ts similarity index 100% rename from src/legacy/ui/public/courier/utils/types.ts rename to src/legacy/core_plugins/data/public/search/utils/types.ts diff --git a/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts b/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts index 864ce3b146689f..176fe68fe4788a 100644 --- a/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts +++ b/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts @@ -17,13 +17,13 @@ * under the License. */ -import { SearchSource as SearchSourceClass } from 'ui/courier'; +import { SearchSource as SearchSourceClass, ISearchSource } from 'ui/courier'; import { Class } from '@kbn/utility-types'; export { Vis, VisParams } from 'ui/vis'; export { VisOptionsProps } from 'ui/vis/editors/default'; export { ValidatedDualRange } from 'ui/validated_range'; -export { SearchSourceFields } from 'ui/courier/types'; +export { SearchSourceFields } from '../../data/public'; -export type SearchSource = Class; +export type SearchSource = Class; export const SearchSource = SearchSourceClass; diff --git a/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx b/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx index bad006aa8c7d5a..24efbc2d41f4fd 100644 --- a/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx +++ b/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx @@ -24,6 +24,8 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { flattenHitWrapper } from '../../../../data/public/'; import { DocViewTable } from './table'; +jest.mock('ui/new_platform'); + // @ts-ignore const indexPattern = { fields: { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts index 7f4d7402fcffce..18e15b215523e4 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { SearchSourceContract } from 'ui/courier'; +import { ISearchSource } from 'ui/courier'; import { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; import { extractReferences, injectReferences } from './saved_dashboard_references'; @@ -36,7 +36,7 @@ export interface SavedObjectDashboard extends SavedObject { uiStateJSON?: string; lastSavedTitle: string; refreshInterval?: RefreshInterval; - searchSource: SearchSourceContract; + searchSource: ISearchSource; getQuery(): Query; getFilters(): esFilters.Filter[]; } diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index ae388a243dd2bf..ca169e5f803ab6 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -65,8 +65,8 @@ export { SearchSource, EsQuerySortValue, SortDirection, - SearchSourceContract, -} from '../../../../ui/public/courier'; + ISearchSource, +} from 'ui/courier'; // @ts-ignore export { intervalOptions } from 'ui/agg_types/buckets/_interval_options'; // @ts-ignore diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts index 1351421e1af04f..e7df44e6fe61c7 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts @@ -16,11 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { - EsQuerySortValue, - SortDirection, - SearchSourceContract, -} from '../../../../../kibana_services'; +import { EsQuerySortValue, SortDirection, ISearchSource } from '../../../../../kibana_services'; import { convertTimeValueToIso } from './date_conversion'; import { EsHitRecordList } from '../context'; import { IntervalValue } from './generate_intervals'; @@ -40,7 +36,7 @@ interface RangeQuery { * and filters set. */ export async function fetchHitsInInterval( - searchSource: SearchSourceContract, + searchSource: ISearchSource, timeField: string, sort: [EsQuerySortValue, EsQuerySortValue], sortDir: SortDirection, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts index 14f70570452516..3aa8dea816694f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts @@ -50,7 +50,7 @@ import { getServices, IndexPattern, RequestAdapter, - SearchSourceContract, + ISearchSource, } from '../../kibana_services'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; @@ -89,7 +89,7 @@ export class SearchEmbeddable extends Embeddable private inspectorAdaptors: Adapters; private searchScope?: SearchScope; private panelTitle: string = ''; - private filtersSearchSource?: SearchSourceContract; + private filtersSearchSource?: ISearchSource; private searchInstance?: JQLite; private autoRefreshFetchSubscription?: Subscription; private subscription?: Subscription; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/types.d.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/types.d.ts index c8920e351fccad..d36a6b02e1f7a4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/types.d.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/types.d.ts @@ -17,14 +17,13 @@ * under the License. */ -import { SearchSourceContract } from '../kibana_services'; +import { ISearchSource } from '../kibana_services'; import { SortOrder } from './angular/doc_table/components/table_header/helpers'; -export { SortOrder } from './angular/doc_table/components/table_header/helpers'; export interface SavedSearch { readonly id: string; title: string; - searchSource: SearchSourceContract; + searchSource: ISearchSource; description?: string; columns: string[]; sort: SortOrder[]; diff --git a/src/legacy/core_plugins/kibana/public/visualize_embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize_embeddable/visualize_embeddable.ts index 6aade246d5f653..4d45b0d86023ec 100644 --- a/src/legacy/core_plugins/kibana/public/visualize_embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/visualize_embeddable/visualize_embeddable.ts @@ -29,7 +29,7 @@ import { getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { AppState } from 'ui/state_management/app_state'; import { npStart } from 'ui/new_platform'; import { IExpressionLoaderParams } from 'src/plugins/expressions/public'; -import { SearchSourceContract } from 'ui/courier'; +import { ISearchSource } from 'ui/courier'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { IIndexPattern, @@ -54,7 +54,7 @@ const getKeys = (o: T): Array => Object.keys(o) as Array< export interface VisSavedObject extends SavedObject { vis: Vis; description?: string; - searchSource: SearchSourceContract; + searchSource: ISearchSource; title: string; uiStateJSON?: string; destroy: () => void; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index 0f9e9c11a9dbc2..59c6bddb64521d 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -28,7 +28,7 @@ import { createFormat, } from '../../../legacy_imports'; // eslint-disable-next-line -import { SearchSourceContract } from '../../../../../../ui/public/courier/search_source/search_source'; +import { ISearchSource } from '../../../../../../ui/public/courier/search_source/search_source'; import { Vis, VisParams, VisState } from '..'; interface SchemaConfigParams { @@ -466,7 +466,7 @@ export const buildVislibDimensions = async ( // take a Vis object and decorate it with the necessary params (dimensions, bucket, metric, etc) export const getVisParams = async ( vis: Vis, - params: { searchSource: SearchSourceContract; timeRange?: any; abortSignal?: AbortSignal } + params: { searchSource: ISearchSource; timeRange?: any; abortSignal?: AbortSignal } ) => { const schemas = getSchemas(vis, params.timeRange); let visConfig = cloneDeep(vis.params); @@ -484,7 +484,7 @@ export const getVisParams = async ( export const buildPipeline = async ( vis: Vis, params: { - searchSource: SearchSourceContract; + searchSource: ISearchSource; timeRange?: any; } ) => { diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index 9306ffcaff9fd9..07e0d46e4eb70c 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -27,7 +27,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { SearchSourceContract, FetchOptions } from '../courier/types'; +import { ISearchSource, FetchOptions } from '../courier/types'; import { AggType } from './agg_type'; import { AggGroupNames } from '../vis/editors/default/agg_groups'; import { writeParams } from './agg_params'; @@ -236,7 +236,7 @@ export class AggConfig { * @param {Courier.FetchOptions} options * @return {Promise} */ - onSearchRequestStart(searchSource: SearchSourceContract, options?: FetchOptions) { + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { if (!this.type) { return Promise.resolve(); } diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index b5a7474c99b0e7..ece9c90d09b689 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -32,7 +32,7 @@ import { Schema } from '../vis/editors/default/schemas'; import { AggConfig, AggConfigOptions } from './agg_config'; import { AggGroupNames } from '../vis/editors/default/agg_groups'; import { IndexPattern } from '../../../core_plugins/data/public'; -import { SearchSourceContract, FetchOptions } from '../courier/types'; +import { ISearchSource, FetchOptions } from '../courier/types'; type Schemas = Record; @@ -306,7 +306,7 @@ export class AggConfigs { return _.find(reqAgg.getResponseAggs(), { id }); } - onSearchRequestStart(searchSource: SearchSourceContract, options?: FetchOptions) { + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { return Promise.all( // @ts-ignore this.getRequestAggs().map((agg: AggConfig) => agg.onSearchRequestStart(searchSource, options)) diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/ui/public/agg_types/agg_type.ts index ff4c6875ec6c06..39be1983223bc2 100644 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ b/src/legacy/ui/public/agg_types/agg_type.ts @@ -24,7 +24,7 @@ import { initParams } from './agg_params'; import { AggConfig } from '../vis'; import { AggConfigs } from './agg_configs'; -import { SearchSource } from '../courier'; +import { ISearchSource } from '../courier'; import { Adapters } from '../inspector'; import { BaseParamType } from './param_types/base'; import { AggParamType } from '../agg_types/param_types/agg'; @@ -51,7 +51,7 @@ export interface AggTypeConfig< resp: any, aggConfigs: AggConfigs, aggConfig: TAggConfig, - searchSource: SearchSource, + searchSource: ISearchSource, inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => Promise; @@ -180,7 +180,7 @@ export class AggType< resp: any, aggConfigs: AggConfigs, aggConfig: TAggConfig, - searchSource: SearchSource, + searchSource: ISearchSource, inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => Promise; diff --git a/src/legacy/ui/public/agg_types/buckets/terms.ts b/src/legacy/ui/public/agg_types/buckets/terms.ts index ef9ceb96b005de..c805e53eb2b913 100644 --- a/src/legacy/ui/public/agg_types/buckets/terms.ts +++ b/src/legacy/ui/public/agg_types/buckets/terms.ts @@ -19,7 +19,7 @@ import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { SearchSource, getRequestInspectorStats, getResponseInspectorStats } from '../../courier'; +import { ISearchSource, getRequestInspectorStats, getResponseInspectorStats } from '../../courier'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -90,7 +90,7 @@ export const termsBucketAgg = new BucketAggType({ resp: any, aggConfigs: AggConfigs, aggConfig: IBucketAggConfig, - searchSource: SearchSource, + searchSource: ISearchSource, inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => { diff --git a/src/legacy/ui/public/agg_types/param_types/base.ts b/src/legacy/ui/public/agg_types/param_types/base.ts index bc8fd30e6324e3..f466a9512edf90 100644 --- a/src/legacy/ui/public/agg_types/param_types/base.ts +++ b/src/legacy/ui/public/agg_types/param_types/base.ts @@ -19,7 +19,7 @@ import { AggConfigs } from '../agg_configs'; import { AggConfig } from '../../vis'; -import { SearchSourceContract, FetchOptions } from '../../courier/types'; +import { ISearchSource, FetchOptions } from '../../courier/types'; export class BaseParamType { name: string; @@ -54,7 +54,7 @@ export class BaseParamType { */ modifyAggConfigOnSearchRequestStart: ( aggConfig: TAggConfig, - searchSource?: SearchSourceContract, + searchSource?: ISearchSource, options?: FetchOptions ) => void; diff --git a/src/legacy/ui/public/courier/_index.scss b/src/legacy/ui/public/courier/_index.scss index a5b3911b1d53c8..17382cfa30ce53 100644 --- a/src/legacy/ui/public/courier/_index.scss +++ b/src/legacy/ui/public/courier/_index.scss @@ -1 +1 @@ -@import './fetch/components/shard_failure_modal'; \ No newline at end of file +@import '../../../core_plugins/data/public/search/fetch/components/shard_failure_modal'; \ No newline at end of file diff --git a/src/legacy/ui/public/courier/index.ts b/src/legacy/ui/public/courier/index.ts index c8a06ec2a5518d..709ff1c11e9013 100644 --- a/src/legacy/ui/public/courier/index.ts +++ b/src/legacy/ui/public/courier/index.ts @@ -17,31 +17,46 @@ * under the License. */ -export { SearchSource } from './search_source'; +/** + * Nothing to see here! + * + * Courier / SearchSource has moved to the data plugin, and is being + * re-exported from ui/courier for backwards compatibility. + */ + +import { start as dataStart } from '../../../core_plugins/data/public/legacy'; + +// runtime contracts +export const { defaultSearchStrategy, SearchSource } = dataStart.search; + +// types +export { + ISearchSource, + EsQuerySortValue, // used externally by Discover + FetchOptions, // used externally by AggTypes + SortDirection, // used externally by Discover +} from '../../../core_plugins/data/public'; + +// static code +export { + getRequestInspectorStats, + getResponseInspectorStats, +} from '../../../core_plugins/data/public'; // TODO: Exporting this mock outside of jest tests causes errors because // jest is undefined. Need to refactor the mock to be consistent with // other NP-style mocks. // export { searchSourceMock } from './search_source/mocks'; +// Most these can probably be made internal to the search +// service, so we are temporarily deeply importing them +// until we relocate them to a longer-term home. +/* eslint-disable @kbn/eslint/no-restricted-paths */ export { addSearchStrategy, // used externally by Rollups getSearchErrorType, // used externally by Rollups hasSearchStategyForIndexPattern, // used externally by Discover isDefaultTypeIndexPattern, // used externally by Discover SearchError, // used externally by Visualizations & Rollups -} from './search_strategy'; - -export { - getRequestInspectorStats, - getResponseInspectorStats, -} from './utils/courier_inspector_utils'; - -// types -export { SearchSourceContract } from './search_source'; - -export { - EsQuerySortValue, // used externally by Discover - FetchOptions, // used externally by AggTypes - SortDirection, // used externally by Discover -} from './types'; +} from '../../../core_plugins/data/public/search/search_strategy'; +/* eslint-enable @kbn/eslint/no-restricted-paths */ diff --git a/src/legacy/ui/public/courier/search_source/index.ts b/src/legacy/ui/public/courier/search_source/index.ts index 72170adc2b1296..e7ca48a894b3dc 100644 --- a/src/legacy/ui/public/courier/search_source/index.ts +++ b/src/legacy/ui/public/courier/search_source/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export * from './search_source'; +export { SearchSource, ISearchSource } from '../index'; diff --git a/src/legacy/ui/public/courier/search_source/mocks.ts b/src/legacy/ui/public/courier/search_source/mocks.ts index 2b83f379b4f090..7b7843d22f5198 100644 --- a/src/legacy/ui/public/courier/search_source/mocks.ts +++ b/src/legacy/ui/public/courier/search_source/mocks.ts @@ -36,9 +36,11 @@ * under the License. */ -import { SearchSourceContract } from './search_source'; +// This mock is here for BWC, but will be left behind and replaced by +// the data service mock in the new platform. +import { ISearchSource } from '../index'; -export const searchSourceMock: MockedKeys = { +export const searchSourceMock: MockedKeys = { setPreferredSearchStrategyId: jest.fn(), setFields: jest.fn().mockReturnThis(), setField: jest.fn().mockReturnThis(), diff --git a/src/legacy/ui/public/courier/search_source/search_source.ts b/src/legacy/ui/public/courier/search_source/search_source.ts index e862bb1118a74b..e7ca48a894b3dc 100644 --- a/src/legacy/ui/public/courier/search_source/search_source.ts +++ b/src/legacy/ui/public/courier/search_source/search_source.ts @@ -17,394 +17,4 @@ * under the License. */ -/** - * @name SearchSource - * - * @description A promise-based stream of search results that can inherit from other search sources. - * - * Because filters/queries in Kibana have different levels of persistence and come from different - * places, it is important to keep track of where filters come from for when they are saved back to - * the savedObject store in the Kibana index. To do this, we create trees of searchSource objects - * that can have associated query parameters (index, query, filter, etc) which can also inherit from - * other searchSource objects. - * - * At query time, all of the searchSource objects that have subscribers are "flattened", at which - * point the query params from the searchSource are collected while traversing up the inheritance - * chain. At each link in the chain a decision about how to merge the query params is made until a - * single set of query parameters is created for each active searchSource (a searchSource with - * subscribers). - * - * That set of query parameters is then sent to elasticsearch. This is how the filter hierarchy - * works in Kibana. - * - * Visualize, starting from a new search: - * - * - the `savedVis.searchSource` is set as the `appSearchSource`. - * - The `savedVis.searchSource` would normally inherit from the `appSearchSource`, but now it is - * upgraded to inherit from the `rootSearchSource`. - * - Any interaction with the visualization will still apply filters to the `appSearchSource`, so - * they will be stored directly on the `savedVis.searchSource`. - * - Any interaction with the time filter will be written to the `rootSearchSource`, so those - * filters will not be saved by the `savedVis`. - * - When the `savedVis` is saved to elasticsearch, it takes with it all the filters that are - * defined on it directly, but none of the ones that it inherits from other places. - * - * Visualize, starting from an existing search: - * - * - The `savedVis` loads the `savedSearch` on which it is built. - * - The `savedVis.searchSource` is set to inherit from the `saveSearch.searchSource` and set as - * the `appSearchSource`. - * - The `savedSearch.searchSource`, is set to inherit from the `rootSearchSource`. - * - Then the `savedVis` is written to elasticsearch it will be flattened and only include the - * filters created in the visualize application and will reconnect the filters from the - * `savedSearch` at runtime to prevent losing the relationship - * - * Dashboard search sources: - * - * - Each panel in a dashboard has a search source. - * - The `savedDashboard` also has a searchsource, and it is set as the `appSearchSource`. - * - Each panel's search source inherits from the `appSearchSource`, meaning that they inherit from - * the dashboard search source. - * - When a filter is added to the search box, or via a visualization, it is written to the - * `appSearchSource`. - */ - -import _ from 'lodash'; -import { npSetup } from 'ui/new_platform'; -import { normalizeSortRequest } from './normalize_sort_request'; -import { fetchSoon } from '../fetch'; -import { fieldWildcardFilter } from '../../field_wildcard'; -import { getHighlightRequest, esFilters, esQuery } from '../../../../../plugins/data/public'; -import chrome from '../../chrome'; -import { RequestFailure } from '../fetch/errors'; -import { filterDocvalueFields } from './filter_docvalue_fields'; -import { SearchSourceOptions, SearchSourceFields, SearchRequest } from './types'; -import { FetchOptions, ApiCaller } from '../fetch/types'; - -const esShardTimeout = npSetup.core.injectedMetadata.getInjectedVar('esShardTimeout') as number; -const config = npSetup.core.uiSettings; - -export type SearchSourceContract = Pick; - -export class SearchSource { - private id: string = _.uniqueId('data_source'); - private searchStrategyId?: string; - private parent?: SearchSource; - private requestStartHandlers: Array< - (searchSource: SearchSourceContract, options?: FetchOptions) => Promise - > = []; - private inheritOptions: SearchSourceOptions = {}; - public history: SearchRequest[] = []; - - constructor(private fields: SearchSourceFields = {}) {} - - /** *** - * PUBLIC API - *****/ - - setPreferredSearchStrategyId(searchStrategyId: string) { - this.searchStrategyId = searchStrategyId; - } - - setFields(newFields: SearchSourceFields) { - this.fields = newFields; - return this; - } - - setField(field: K, value: SearchSourceFields[K]) { - if (value == null) { - delete this.fields[field]; - } else { - this.fields[field] = value; - } - return this; - } - - getId() { - return this.id; - } - - getFields() { - return { ...this.fields }; - } - - /** - * Get fields from the fields - */ - getField(field: K, recurse = true): SearchSourceFields[K] { - if (!recurse || this.fields[field] !== void 0) { - return this.fields[field]; - } - const parent = this.getParent(); - return parent && parent.getField(field); - } - - /** - * Get the field from our own fields, don't traverse up the chain - */ - getOwnField(field: K): SearchSourceFields[K] { - return this.getField(field, false); - } - - create() { - return new SearchSource(); - } - - createCopy() { - const newSearchSource = new SearchSource(); - newSearchSource.setFields({ ...this.fields }); - // when serializing the internal fields we lose the internal classes used in the index - // pattern, so we have to set it again to workaround this behavior - newSearchSource.setField('index', this.getField('index')); - newSearchSource.setParent(this.getParent()); - return newSearchSource; - } - - createChild(options = {}) { - const childSearchSource = new SearchSource(); - childSearchSource.setParent(this, options); - return childSearchSource; - } - - /** - * Set a searchSource that this source should inherit from - * @param {SearchSource} parent - the parent searchSource - * @param {SearchSourceOptions} options - the inherit options - * @return {this} - chainable - */ - setParent(parent?: SearchSourceContract, options: SearchSourceOptions = {}) { - this.parent = parent as SearchSource; - this.inheritOptions = options; - return this; - } - - /** - * Get the parent of this SearchSource - * @return {undefined|searchSource} - */ - getParent() { - return this.parent; - } - - /** - * Fetch this source and reject the returned Promise on error - * - * @async - */ - async fetch(options: FetchOptions = {}) { - const $injector = await chrome.dangerouslyGetActiveInjector(); - const es = $injector.get('es') as ApiCaller; - - await this.requestIsStarting(options); - - const searchRequest = await this.flatten(); - this.history = [searchRequest]; - - const response = await fetchSoon( - searchRequest, - { - ...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }), - ...options, - }, - { es, config, esShardTimeout } - ); - - if (response.error) { - throw new RequestFailure(null, response); - } - - return response; - } - - /** - * Add a handler that will be notified whenever requests start - * @param {Function} handler - * @return {undefined} - */ - onRequestStart( - handler: (searchSource: SearchSourceContract, options?: FetchOptions) => Promise - ) { - this.requestStartHandlers.push(handler); - } - - async getSearchRequestBody() { - const searchRequest = await this.flatten(); - return searchRequest.body; - } - - /** - * Completely destroy the SearchSource. - * @return {undefined} - */ - destroy() { - this.requestStartHandlers.length = 0; - } - - /** **** - * PRIVATE APIS - ******/ - - /** - * Called by requests of this search source when they are started - * @param {Courier.Request} request - * @param options - * @return {Promise} - */ - private requestIsStarting(options: FetchOptions = {}) { - const handlers = [...this.requestStartHandlers]; - // If callParentStartHandlers has been set to true, we also call all - // handlers of parent search sources. - if (this.inheritOptions.callParentStartHandlers) { - let searchSource = this.getParent(); - while (searchSource) { - handlers.push(...searchSource.requestStartHandlers); - searchSource = searchSource.getParent(); - } - } - - return Promise.all(handlers.map(fn => fn(this, options))); - } - - /** - * Used to merge properties into the data within ._flatten(). - * The data is passed in and modified by the function - * - * @param {object} data - the current merged data - * @param {*} val - the value at `key` - * @param {*} key - The key of `val` - * @return {undefined} - */ - private mergeProp( - data: SearchRequest, - val: SearchSourceFields[K], - key: K - ) { - val = typeof val === 'function' ? val(this) : val; - if (val == null || !key) return; - - const addToRoot = (rootKey: string, value: any) => { - data[rootKey] = value; - }; - - /** - * Add the key and val to the body of the request - */ - const addToBody = (bodyKey: string, value: any) => { - // ignore if we already have a value - if (data.body[bodyKey] == null) { - data.body[bodyKey] = value; - } - }; - - switch (key) { - case 'filter': - return addToRoot('filters', (data.filters || []).concat(val)); - case 'query': - return addToRoot(key, (data[key] || []).concat(val)); - case 'fields': - const fields = _.uniq((data[key] || []).concat(val)); - return addToRoot(key, fields); - case 'index': - case 'type': - case 'highlightAll': - return key && data[key] == null && addToRoot(key, val); - case 'searchAfter': - return addToBody('search_after', val); - case 'source': - return addToBody('_source', val); - case 'sort': - const sort = normalizeSortRequest(val, this.getField('index'), config.get('sort:options')); - return addToBody(key, sort); - default: - return addToBody(key, val); - } - } - - /** - * Walk the inheritance chain of a source and return its - * flat representation (taking into account merging rules) - * @returns {Promise} - * @resolved {Object|null} - the flat data of the SearchSource - */ - private mergeProps(root = this, searchRequest: SearchRequest = { body: {} }) { - Object.entries(this.fields).forEach(([key, value]) => { - this.mergeProp(searchRequest, value, key as keyof SearchSourceFields); - }); - if (this.parent) { - this.parent.mergeProps(root, searchRequest); - } - return searchRequest; - } - - private flatten() { - const searchRequest = this.mergeProps(); - - searchRequest.body = searchRequest.body || {}; - const { body, index, fields, query, filters, highlightAll } = searchRequest; - - const computedFields = index ? index.getComputedFields() : {}; - - body.stored_fields = computedFields.storedFields; - body.script_fields = body.script_fields || {}; - _.extend(body.script_fields, computedFields.scriptFields); - - const defaultDocValueFields = computedFields.docvalueFields - ? computedFields.docvalueFields - : []; - body.docvalue_fields = body.docvalue_fields || defaultDocValueFields; - - if (!body.hasOwnProperty('_source') && index) { - body._source = index.getSourceFiltering(); - } - - if (body._source) { - // exclude source fields for this index pattern specified by the user - const filter = fieldWildcardFilter(body._source.excludes, config.get('metaFields')); - body.docvalue_fields = body.docvalue_fields.filter((docvalueField: any) => - filter(docvalueField.field) - ); - } - - // if we only want to search for certain fields - if (fields) { - // filter out the docvalue_fields, and script_fields to only include those that we are concerned with - body.docvalue_fields = filterDocvalueFields(body.docvalue_fields, fields); - body.script_fields = _.pick(body.script_fields, fields); - - // request the remaining fields from both stored_fields and _source - const remainingFields = _.difference(fields, _.keys(body.script_fields)); - body.stored_fields = remainingFields; - _.set(body, '_source.includes', remainingFields); - } - - const esQueryConfigs = esQuery.getEsQueryConfig(config); - body.query = esQuery.buildEsQuery(index, query, filters, esQueryConfigs); - - if (highlightAll && body.query) { - body.highlight = getHighlightRequest(body.query, config.get('doc_table:highlight')); - delete searchRequest.highlightAll; - } - - const translateToQuery = (filter: esFilters.Filter) => filter && (filter.query || filter); - - // re-write filters within filter aggregations - (function recurse(aggBranch) { - if (!aggBranch) return; - Object.keys(aggBranch).forEach(function(id) { - const agg = aggBranch[id]; - - if (agg.filters) { - // translate filters aggregations - const { filters: aggFilters } = agg.filters; - Object.keys(aggFilters).forEach(filterId => { - aggFilters[filterId] = translateToQuery(aggFilters[filterId]); - }); - } - - recurse(agg.aggs || agg.aggregations); - }); - })(body.aggs || body.aggregations); - - return searchRequest; - } -} +export { SearchSource, ISearchSource } from '../index'; diff --git a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts b/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts index 5be4fef0766555..55dee19cae32a8 100644 --- a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts +++ b/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts @@ -17,65 +17,8 @@ * under the License. */ -import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; -import { addSearchStrategy } from './search_strategy_registry'; -import { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; -import { - getSearchParams, - getMSearchParams, - getPreference, - getTimeout, -} from '../fetch/get_search_params'; - -export const defaultSearchStrategy: SearchStrategyProvider = { - id: 'default', - - search: params => { - return params.config.get('courier:batchSearches') ? msearch(params) : search(params); - }, - - isViable: indexPattern => { - return indexPattern && isDefaultTypeIndexPattern(indexPattern); - }, -}; - -function msearch({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { - const inlineRequests = searchRequests.map(({ index, body, search_type: searchType }) => { - const inlineHeader = { - index: index.title || index, - search_type: searchType, - ignore_unavailable: true, - preference: getPreference(config), - }; - const inlineBody = { - ...body, - timeout: getTimeout(esShardTimeout), - }; - return `${JSON.stringify(inlineHeader)}\n${JSON.stringify(inlineBody)}`; - }); - - const searching = es.msearch({ - ...getMSearchParams(config), - body: `${inlineRequests.join('\n')}\n`, - }); - return { - searching: searching.then(({ responses }) => responses), - abort: searching.abort, - }; -} - -function search({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { - const abortController = new AbortController(); - const searchParams = getSearchParams(config, esShardTimeout); - const promises = searchRequests.map(({ index, body }) => { - const searching = es.search({ index: index.title || index, body, ...searchParams }); - abortController.signal.addEventListener('abort', searching.abort); - return searching.catch(({ response }) => JSON.parse(response)); - }); - return { - searching: Promise.all(promises), - abort: () => abortController.abort(), - }; -} +import { addSearchStrategy, defaultSearchStrategy } from '../index'; addSearchStrategy(defaultSearchStrategy); + +export { defaultSearchStrategy }; diff --git a/src/legacy/ui/public/courier/search_strategy/index.ts b/src/legacy/ui/public/courier/search_strategy/index.ts index 229d0cbb1da5da..1dce0316596d07 100644 --- a/src/legacy/ui/public/courier/search_strategy/index.ts +++ b/src/legacy/ui/public/courier/search_strategy/index.ts @@ -20,10 +20,6 @@ export { addSearchStrategy, hasSearchStategyForIndexPattern, - getSearchStrategyById, - getSearchStrategyForSearchRequest, -} from './search_strategy_registry'; - -export { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; - -export { SearchError, getSearchErrorType } from './search_error'; + isDefaultTypeIndexPattern, + SearchError, +} from '../index'; diff --git a/src/legacy/ui/public/courier/search_strategy/search_error.ts b/src/legacy/ui/public/courier/search_strategy/search_error.ts index d4042fb17499cb..a815ac4ff008f4 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_error.ts +++ b/src/legacy/ui/public/courier/search_strategy/search_error.ts @@ -17,46 +17,4 @@ * under the License. */ -interface SearchErrorOptions { - status: string; - title: string; - message: string; - path: string; - type: string; -} - -export class SearchError extends Error { - public name: string; - public status: string; - public title: string; - public message: string; - public path: string; - public type: string; - - constructor({ status, title, message, path, type }: SearchErrorOptions) { - super(message); - this.name = 'SearchError'; - this.status = status; - this.title = title; - this.message = message; - this.path = path; - this.type = type; - - // captureStackTrace is only available in the V8 engine, so any browser using - // a different JS engine won't have access to this method. - if (Error.captureStackTrace) { - Error.captureStackTrace(this, SearchError); - } - - // Babel doesn't support traditional `extends` syntax for built-in classes. - // https://babeljs.io/docs/en/caveats/#classes - Object.setPrototypeOf(this, SearchError.prototype); - } -} - -export function getSearchErrorType({ message }: Pick) { - const msg = message.toLowerCase(); - if (msg.indexOf('unsupported query') > -1) { - return 'UNSUPPORTED_QUERY'; - } -} +export { SearchError } from '../index'; diff --git a/src/legacy/ui/public/courier/types.ts b/src/legacy/ui/public/courier/types.ts index 23d74ce6a57da8..75035ceef321fa 100644 --- a/src/legacy/ui/public/courier/types.ts +++ b/src/legacy/ui/public/courier/types.ts @@ -17,7 +17,9 @@ * under the License. */ -export * from './fetch/types'; -export * from './search_source/types'; -export * from './search_strategy/types'; -export * from './utils/types'; +export { + ISearchSource, + EsQuerySortValue, // used externally by Discover + FetchOptions, // used externally by AggTypes + SortDirection, // used externally by Discover +} from './index'; diff --git a/src/legacy/ui/public/saved_objects/types.ts b/src/legacy/ui/public/saved_objects/types.ts index c4e6438424046f..2578c2015e819f 100644 --- a/src/legacy/ui/public/saved_objects/types.ts +++ b/src/legacy/ui/public/saved_objects/types.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + import { ChromeStart, OverlayStart, @@ -23,7 +24,7 @@ import { SavedObjectAttributes, SavedObjectReference, } from 'kibana/public'; -import { SearchSource, SearchSourceContract } from 'ui/courier'; +import { ISearchSource } from 'ui/courier'; import { IIndexPattern, IndexPatternsContract } from '../../../../plugins/data/public'; export interface SavedObject { @@ -46,7 +47,7 @@ export interface SavedObject { lastSavedTitle: string; migrationVersion?: Record; save: (saveOptions: SavedObjectSaveOpts) => Promise; - searchSource?: SearchSourceContract; + searchSource?: ISearchSource; showInRecentlyAccessed: boolean; title: string; } @@ -88,7 +89,7 @@ export interface SavedObjectConfig { mapping?: any; migrationVersion?: Record; path?: string; - searchSource?: SearchSource | boolean; + searchSource?: ISearchSource | boolean; type?: string; } diff --git a/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts b/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts index a9203415321faa..5054c34118f786 100644 --- a/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts +++ b/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts @@ -24,13 +24,13 @@ import { toastNotifications } from 'ui/notify'; import { AggConfig } from 'ui/vis'; import { timefilter } from 'ui/timefilter'; import { Vis } from '../../../vis'; -import { SearchSource, SearchSourceContract } from '../../../courier'; +import { SearchSource, ISearchSource } from '../../../courier'; import { esFilters, Query } from '../../../../../../plugins/data/public'; interface QueryGeohashBoundsParams { filters?: esFilters.Filter[]; query?: Query; - searchSource?: SearchSourceContract; + searchSource?: ISearchSource; } /** diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts index 8f124c25542c75..ffb8be1deaa9ef 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts @@ -8,6 +8,8 @@ import moment from 'moment'; import { mergeTables } from './merge_tables'; import { KibanaDatatable } from 'src/plugins/expressions/public'; +jest.mock('ui/new_platform'); + describe('lens_merge_tables', () => { it('should produce a row with the nested table as defined', () => { const sampleTable1: KibanaDatatable = { diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx index ea9fa516d4d916..2bd6c7106a952a 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx @@ -14,19 +14,35 @@ import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; -jest.mock('ui/new_platform', () => ({ - npStart: { - core: { - uiSettings: { - get: (path: string) => { - if (path === 'histogram:maxBars') { - return 10; - } +jest.mock('ui/new_platform', () => { + // Due to the way we are handling shims in the NP migration, we need + // to mock core here so that upstream services don't cause these + // tests to fail. Ordinarly `jest.mock('ui/new_platform')` would be + // sufficient, however we need to mock one of the `uiSettings` return + // values for this suite, so we must manually assemble the mock. + // Because babel hoists `jest` we must use an inline `require` + // to ensure the core mocks are available (`jest.doMock` doesn't + // work in this case). This mock should be able to be replaced + // altogether once Lens has migrated to the new platform. + const { coreMock } = require('src/core/public/mocks'); // eslint-disable-line @typescript-eslint/no-var-requires + return { + npSetup: { + core: coreMock.createSetup(), + }, + npStart: { + core: { + ...coreMock.createStart(), + uiSettings: { + get: (path: string) => { + if (path === 'histogram:maxBars') { + return 10; + } + }, }, }, }, - }, -})); + }; +}); const defaultOptions = { storage: {} as IStorageWrapper, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b7bac7dd170ed2..c79969154d05c0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -261,24 +261,6 @@ "common.ui.aggTypes.timeInterval.scaledHelpText": "現在 {bucketDescription} にスケーリングされています", "common.ui.aggTypes.timeInterval.selectIntervalPlaceholder": "間隔を選択", "common.ui.aggTypes.timeInterval.selectOptionHelpText": "オプションを選択するかカスタム値を作成します。例30s、20m、24h、2d、1w、1M", - "common.ui.courier.fetch.requestTimedOutNotificationMessage": "リクエストがタイムアウトしたため、データが不完全な可能性があります", - "common.ui.courier.fetch.shardsFailedNotificationMessage": "{shardsTotal} 件中 {shardsFailed} 件のシャードでエラーが発生しました", - "common.ui.courier.hitsDescription": "クエリにより返されたドキュメントの数です。", - "common.ui.courier.hitsLabel": "ヒット数", - "common.ui.courier.hitsTotalDescription": "クエリに一致するドキュメントの数です。", - "common.ui.courier.hitsTotalLabel": "ヒット数 (合計)", - "common.ui.courier.indexPatternDescription": "Elasticsearch インデックスに接続したインデックスパターンです。", - "common.ui.courier.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", - "common.ui.courier.indexPatternIdLabel": "インデックスパターン ID", - "common.ui.courier.indexPatternLabel": "インデックスパターン", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription": "検索リクエストの検索方法が見つかりませんでした", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle": "検索方法が登録されていません", - "common.ui.courier.queryTimeDescription": "クエリの処理の所要時間です。リクエストの送信やブラウザでのパースの時間は含まれません。", - "common.ui.courier.queryTimeLabel": "クエリ時間", - "common.ui.courier.queryTimeValue": "{queryTime}ms", - "common.ui.courier.requestTimeDescription": "ブラウザから Elasticsearch にリクエストが送信され返されるまでの所要時間です。リクエストがキューで待機していた時間は含まれません。", - "common.ui.courier.requestTimeLabel": "リクエスト時間", - "common.ui.courier.requestTimeValue": "{requestTime}ms", "common.ui.directives.fieldNameIcons.booleanAriaLabel": "ブールフィールド", "common.ui.directives.fieldNameIcons.conflictFieldAriaLabel": "矛盾フィールド", "common.ui.directives.fieldNameIcons.dateFieldAriaLabel": "日付フィールド", @@ -541,20 +523,6 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "バウンドを取得できませんでした", "common.ui.welcomeErrorMessage": "Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。", "common.ui.welcomeMessage": "Kibana を読み込み中", - "common.ui.courier.fetch.shardsFailedModal.close": "閉じる", - "common.ui.courier.fetch.shardsFailedModal.copyToClipboard": "応答をクリップボードにコピー", - "common.ui.courier.fetch.shardsFailedModal.failureHeader": "{failureName} で {failureDetails}", - "common.ui.courier.fetch.shardsFailedModal.showDetails": "詳細を表示", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse": "応答", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー", - "common.ui.courier.fetch.shardsFailedModal.tableColIndex": "インデックス", - "common.ui.courier.fetch.shardsFailedModal.tableColNode": "ノード", - "common.ui.courier.fetch.shardsFailedModal.tableColReason": "理由", - "common.ui.courier.fetch.shardsFailedModal.tableColShard": "シャード", - "common.ui.courier.fetch.shardsFailedModal.tableRowCollapse": "{rowDescription} を折りたたむ", - "common.ui.courier.fetch.shardsFailedModal.tableRowExpand": "{rowDescription} を展開する", - "common.ui.courier.fetch.shardsFailedNotificationDescription": "表示されているデータは不完全か誤りの可能性があります。", "common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "地理情報図形", "common.ui.vis.editors.agg.errorsAriaLabel": "集約にエラーがあります", "common.ui.vislib.heatmap.maxBucketsText": "定義された数列が多すぎます ({nr}).構成されている最高値は {max} です。", @@ -873,6 +841,38 @@ "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} の説明", "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "選択されたクエリボタン {savedQueryName} を保存しました。変更を破棄するには押してください。", "data.search.searchBar.savedQueryPopoverTitleText": "保存されたクエリ", + "data.search.searchSource.fetch.shardsFailedModal.close": "閉じる", + "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "応答をクリップボードにコピー", + "data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureName} で {failureDetails}", + "data.search.searchSource.fetch.shardsFailedModal.showDetails": "詳細を表示", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "応答", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー", + "data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "インデックス", + "data.search.searchSource.fetch.shardsFailedModal.tableColNode": "ノード", + "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "理由", + "data.search.searchSource.fetch.shardsFailedModal.tableColShard": "シャード", + "data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "{rowDescription} を折りたたむ", + "data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "{rowDescription} を展開する", + "data.search.searchSource.fetch.shardsFailedNotificationDescription": "表示されているデータは不完全か誤りの可能性があります。", + "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "リクエストがタイムアウトしたため、データが不完全な可能性があります", + "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 件中 {shardsFailed} 件のシャードでエラーが発生しました", + "data.search.searchSource.hitsDescription": "クエリにより返されたドキュメントの数です。", + "data.search.searchSource.hitsLabel": "ヒット数", + "data.search.searchSource.hitsTotalDescription": "クエリに一致するドキュメントの数です。", + "data.search.searchSource.hitsTotalLabel": "ヒット数 (合計)", + "data.search.searchSource.indexPatternDescription": "Elasticsearch インデックスに接続したインデックスパターンです。", + "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", + "data.search.searchSource.indexPatternIdLabel": "インデックスパターン ID", + "data.search.searchSource.indexPatternLabel": "インデックスパターン", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "検索リクエストの検索方法が見つかりませんでした", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "検索方法が登録されていません", + "data.search.searchSource.queryTimeDescription": "クエリの処理の所要時間です。リクエストの送信やブラウザでのパースの時間は含まれません。", + "data.search.searchSource.queryTimeLabel": "クエリ時間", + "data.search.searchSource.queryTimeValue": "{queryTime}ms", + "data.search.searchSource.requestTimeDescription": "ブラウザから Elasticsearch にリクエストが送信され返されるまでの所要時間です。リクエストがキューで待機していた時間は含まれません。", + "data.search.searchSource.requestTimeLabel": "リクエスト時間", + "data.search.searchSource.requestTimeValue": "{requestTime}ms", "data.filter.filterEditor.operatorSelectPlaceholderSelect": "選択してください", "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "待機中", "data.filter.filterEditor.rangeInputLabel": "範囲", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7ade936ba10445..34559ba9f95be2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -261,24 +261,6 @@ "common.ui.aggTypes.timeInterval.scaledHelpText": "当前缩放至 {bucketDescription}", "common.ui.aggTypes.timeInterval.selectIntervalPlaceholder": "选择时间间隔", "common.ui.aggTypes.timeInterval.selectOptionHelpText": "选择选项或创建定制值示例:30s、20m、24h、2d、1w、1M", - "common.ui.courier.fetch.requestTimedOutNotificationMessage": "由于您的请求超时,因此数据可能不完整", - "common.ui.courier.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败", - "common.ui.courier.hitsDescription": "查询返回的文档数目。", - "common.ui.courier.hitsLabel": "命中", - "common.ui.courier.hitsTotalDescription": "匹配查询的文档数目。", - "common.ui.courier.hitsTotalLabel": "命中(总计)", - "common.ui.courier.indexPatternDescription": "连接到 Elasticsearch 索引的索引模式。", - "common.ui.courier.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", - "common.ui.courier.indexPatternIdLabel": "索引模式 ID", - "common.ui.courier.indexPatternLabel": "索引模式", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription": "无法为该搜索请求找到搜索策略", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle": "未注册任何搜索策略", - "common.ui.courier.queryTimeDescription": "处理查询所花费的时间。不包括发送请求或在浏览器中解析它的时间。", - "common.ui.courier.queryTimeLabel": "查询时间", - "common.ui.courier.queryTimeValue": "{queryTime}ms", - "common.ui.courier.requestTimeDescription": "请求从浏览器到 Elasticsearch 以及返回的时间。不包括请求在队列中等候的时间。", - "common.ui.courier.requestTimeLabel": "请求时间", - "common.ui.courier.requestTimeValue": "{requestTime}ms", "common.ui.directives.fieldNameIcons.booleanAriaLabel": "布尔字段", "common.ui.directives.fieldNameIcons.conflictFieldAriaLabel": "冲突字段", "common.ui.directives.fieldNameIcons.dateFieldAriaLabel": "日期字段", @@ -542,20 +524,6 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "无法获取边界", "common.ui.welcomeErrorMessage": "Kibana 未正确加载。检查服务器输出以了解详情。", "common.ui.welcomeMessage": "正在加载 Kibana", - "common.ui.courier.fetch.shardsFailedModal.close": "关闭", - "common.ui.courier.fetch.shardsFailedModal.copyToClipboard": "将响应复制到剪贴板", - "common.ui.courier.fetch.shardsFailedModal.failureHeader": "{failureDetails} 时为 {failureName}", - "common.ui.courier.fetch.shardsFailedModal.showDetails": "显示详情", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest": "请求", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse": "响应", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误", - "common.ui.courier.fetch.shardsFailedModal.tableColIndex": "索引", - "common.ui.courier.fetch.shardsFailedModal.tableColNode": "节点", - "common.ui.courier.fetch.shardsFailedModal.tableColReason": "原因", - "common.ui.courier.fetch.shardsFailedModal.tableColShard": "分片", - "common.ui.courier.fetch.shardsFailedModal.tableRowCollapse": "折叠 {rowDescription}", - "common.ui.courier.fetch.shardsFailedModal.tableRowExpand": "展开 {rowDescription}", - "common.ui.courier.fetch.shardsFailedNotificationDescription": "您正在查看的数据可能不完整或有错误。", "common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "几何形状字段", "common.ui.vis.editors.agg.errorsAriaLabel": "聚合有错误", "common.ui.vislib.heatmap.maxBucketsText": "定义了过多的序列 ({nr})。配置的最大值为 {max}。", @@ -874,6 +842,38 @@ "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} 描述", "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "已保存查询按钮已选择 {savedQueryName}。按下可清除任何更改。", "data.search.searchBar.savedQueryPopoverTitleText": "已保存查询", + "data.search.searchSource.fetch.shardsFailedModal.close": "关闭", + "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "将响应复制到剪贴板", + "data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureDetails} 时为 {failureName}", + "data.search.searchSource.fetch.shardsFailedModal.showDetails": "显示详情", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "请求", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "响应", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误", + "data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "索引", + "data.search.searchSource.fetch.shardsFailedModal.tableColNode": "节点", + "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "原因", + "data.search.searchSource.fetch.shardsFailedModal.tableColShard": "分片", + "data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "折叠 {rowDescription}", + "data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "展开 {rowDescription}", + "data.search.searchSource.fetch.shardsFailedNotificationDescription": "您正在查看的数据可能不完整或有错误。", + "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "由于您的请求超时,因此数据可能不完整", + "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败", + "data.search.searchSource.hitsDescription": "查询返回的文档数目。", + "data.search.searchSource.hitsLabel": "命中", + "data.search.searchSource.hitsTotalDescription": "匹配查询的文档数目。", + "data.search.searchSource.hitsTotalLabel": "命中(总计)", + "data.search.searchSource.indexPatternDescription": "连接到 Elasticsearch 索引的索引模式。", + "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", + "data.search.searchSource.indexPatternIdLabel": "索引模式 ID", + "data.search.searchSource.indexPatternLabel": "索引模式", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "无法为该搜索请求找到搜索策略", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "未注册任何搜索策略", + "data.search.searchSource.queryTimeDescription": "处理查询所花费的时间。不包括发送请求或在浏览器中解析它的时间。", + "data.search.searchSource.queryTimeLabel": "查询时间", + "data.search.searchSource.queryTimeValue": "{queryTime}ms", + "data.search.searchSource.requestTimeDescription": "请求从浏览器到 Elasticsearch 以及返回的时间。不包括请求在队列中等候的时间。", + "data.search.searchSource.requestTimeLabel": "请求时间", + "data.search.searchSource.requestTimeValue": "{requestTime}ms", "data.filter.filterEditor.operatorSelectPlaceholderSelect": "选择", "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "正在等候", "data.filter.filterEditor.rangeInputLabel": "范围",