From de10eae21774bd58221fa6c40501c9a6417959b3 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 1 Mar 2021 11:42:40 -0700 Subject: [PATCH 01/51] [Reporting-CSV Export] Re-write CSV Export using SearchSource --- ...-plugins-data-public.searchsourcefields.md | 1 + ...gins-data-public.searchsourcefields.pit.md | 14 + .../search/search_source/search_source.ts | 2 + .../data/common/search/search_source/types.ts | 5 +- src/plugins/data/public/public.api.md | 5 + .../components/top_nav/get_top_nav_links.ts | 3 +- .../helpers/get_sharing_data.test.ts | 62 +- .../application/helpers/get_sharing_data.ts | 84 +- src/plugins/discover/public/index.ts | 1 + src/plugins/discover/public/shared/index.ts | 14 + x-pack/plugins/reporting/common/constants.ts | 10 +- x-pack/plugins/reporting/common/types.ts | 3 +- .../components/reporting_panel_content.tsx | 10 +- .../get_csv_panel_action.test.ts | 15 +- .../panel_actions/get_csv_panel_action.tsx | 62 +- .../register_csv_reporting.tsx | 20 +- x-pack/plugins/reporting/server/core.ts | 14 + .../server/export_types/common/index.ts | 1 - .../generate_csv/check_cells_for_formulas.ts | 4 +- .../export_types/csv/generate_csv/index.ts | 11 +- .../server/export_types/csv/types.d.ts | 7 +- .../csv_from_savedobject/create_job.ts | 96 - .../csv_from_savedobject/execute_job.ts | 80 - .../lib/get_csv_job.test.ts | 340 --- .../csv_from_savedobject/lib/get_csv_job.ts | 155 - .../lib/get_data_source.ts | 56 - .../lib/get_filters.test.ts | 208 -- .../csv_from_savedobject/lib/get_filters.ts | 55 - .../csv_from_savedobject/types.d.ts | 153 - .../csv_searchsource/create_job.ts | 30 + .../csv_searchsource/execute_job.test.ts | 75 + .../csv_searchsource/execute_job.ts | 50 + .../generate_csv/cell_has_formula.ts | 0 .../generate_csv/escape_value.test.ts | 0 .../generate_csv/escape_value.ts | 0 .../generate_csv/generate_csv.test.ts | 551 ++++ .../generate_csv/generate_csv.ts | 394 +++ .../generate_csv/get_export_settings.test.ts | 83 + .../generate_csv/get_export_settings.ts | 85 + .../csv_searchsource/generate_csv/index.ts | 8 + .../max_size_string_builder.test.ts | 0 .../generate_csv/max_size_string_builder.ts | 0 .../export_types/csv_searchsource/index.ts | 40 + .../metadata.ts | 6 +- .../export_types/csv_searchsource/types.d.ts | 18 + .../csv_searchsource_immediate/execute_job.ts | 81 + .../index.ts | 13 +- .../csv_searchsource_immediate/metadata.ts | 13 + .../csv_searchsource_immediate/types.d.ts | 24 + .../reporting/server/lib/enqueue_job.ts | 6 +- .../server/lib/export_types_registry.ts | 8 +- x-pack/plugins/reporting/server/plugin.ts | 2 + ...diate.ts => csv_searchsource_immediate.ts} | 44 +- .../reporting/server/routes/generation.ts | 2 +- .../server/routes/lib/get_document_payload.ts | 6 +- .../routes/lib/get_job_params_from_request.ts | 22 - .../create_mock_reportingplugin.ts | 35 +- x-pack/plugins/reporting/server/types.ts | 7 +- .../reporting_usage_collector.test.ts.snap | 24 + .../server/usage/decorate_range_stats.ts | 8 +- .../reporting/__snapshots__/download_csv.snap | 47 + .../apps/dashboard/reporting/download_csv.ts | 160 +- .../discover/__snapshots__/reporting.snap | 59 +- .../reporting/hugedata/data.json.gz | Bin 33745 -> 33885 bytes .../reporting/hugedata/mappings.json | 2590 ++++++++++++++--- .../reporting/scripted_small2/data.json.gz | Bin 4436 -> 0 bytes .../reporting/scripted_small2/mappings.json | 2217 -------------- .../reporting_api_integration/fixtures.ts | 263 +- .../reporting_and_security.config.ts | 1 + .../csv_searchsource_immediate.snap | 251 ++ .../reporting_and_security/csv_job_params.ts | 6 +- .../csv_saved_search.ts | 411 --- .../csv_searchsource_immediate.ts | 344 +++ .../reporting_and_security/index.ts | 2 +- .../reporting_without_security/job_apis.ts | 8 +- 75 files changed, 4727 insertions(+), 4758 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md create mode 100644 src/plugins/discover/public/shared/index.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/create_job.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_data_source.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.test.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.ts delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/create_job.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.test.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts rename x-pack/plugins/reporting/server/export_types/{csv => csv_searchsource}/generate_csv/cell_has_formula.ts (100%) rename x-pack/plugins/reporting/server/export_types/{csv => csv_searchsource}/generate_csv/escape_value.test.ts (100%) rename x-pack/plugins/reporting/server/export_types/{csv => csv_searchsource}/generate_csv/escape_value.ts (100%) create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.test.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/index.ts rename x-pack/plugins/reporting/server/export_types/{csv => csv_searchsource}/generate_csv/max_size_string_builder.test.ts (100%) rename x-pack/plugins/reporting/server/export_types/{csv => csv_searchsource}/generate_csv/max_size_string_builder.ts (100%) create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/index.ts rename x-pack/plugins/reporting/server/export_types/{csv_from_savedobject => csv_searchsource}/metadata.ts (65%) create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/types.d.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts rename x-pack/plugins/reporting/server/export_types/{csv_from_savedobject => csv_searchsource_immediate}/index.ts (75%) create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/metadata.ts create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/types.d.ts rename x-pack/plugins/reporting/server/routes/{generate_from_savedobject_immediate.ts => csv_searchsource_immediate.ts} (55%) delete mode 100644 x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts create mode 100644 x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap delete mode 100644 x-pack/test/functional/es_archives/reporting/scripted_small2/data.json.gz delete mode 100644 x-pack/test/functional/es_archives/reporting/scripted_small2/mappings.json create mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap delete mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/csv_saved_search.ts create mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md index d0f53936eb56a..bd85d67772cd9 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md @@ -25,6 +25,7 @@ export interface SearchSourceFields | [highlightAll](./kibana-plugin-plugins-data-public.searchsourcefields.highlightall.md) | boolean | | | [index](./kibana-plugin-plugins-data-public.searchsourcefields.index.md) | IndexPattern | | | [parent](./kibana-plugin-plugins-data-public.searchsourcefields.parent.md) | SearchSourceFields | | +| [pit](./kibana-plugin-plugins-data-public.searchsourcefields.pit.md) | {
id: string;
keep_alive?: string;
} | | | [query](./kibana-plugin-plugins-data-public.searchsourcefields.query.md) | Query | [Query](./kibana-plugin-plugins-data-public.query.md) | | [searchAfter](./kibana-plugin-plugins-data-public.searchsourcefields.searchafter.md) | EsQuerySearchAfter | | | [size](./kibana-plugin-plugins-data-public.searchsourcefields.size.md) | number | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md new file mode 100644 index 0000000000000..c7e426d3f47ca --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md @@ -0,0 +1,14 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchSourceFields](./kibana-plugin-plugins-data-public.searchsourcefields.md) > [pit](./kibana-plugin-plugins-data-public.searchsourcefields.pit.md) + +## SearchSourceFields.pit property + +Signature: + +```typescript +pit?: { + id: string; + keep_alive?: string; + }; +``` diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index f11e7f06b6ab9..4f0b88f840d60 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -439,6 +439,8 @@ export class SearchSource { getConfig(UI_SETTINGS.SORT_OPTIONS) ); return addToBody(key, sort); + case 'pit': + return addToRoot(key, val); default: return addToBody(key, val); } diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index a178b38693d92..0fbbaec5c4a6a 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -100,7 +100,10 @@ export interface SearchSourceFields { searchAfter?: EsQuerySearchAfter; timeout?: string; terminate_after?: number; - + pit?: { + id: string; + keep_alive?: string; + }; parent?: SearchSourceFields; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 9720395881ea3..9f6c7e424cdbf 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2438,6 +2438,11 @@ export interface SearchSourceFields { // (undocumented) parent?: SearchSourceFields; // (undocumented) + pit?: { + id: string; + keep_alive?: string; + }; + // (undocumented) query?: Query; // Warning: (ae-forgotten-export) The symbol "EsQuerySearchAfter" needs to be exported by the entry point index.d.ts // diff --git a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.ts b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.ts index a1215836f9c5f..65fef2e4d030f 100644 --- a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.ts +++ b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.ts @@ -97,8 +97,7 @@ export const getTopNavLinks = ({ const sharingData = await getSharingData( searchSource, state.appStateContainer.getState(), - services.uiSettings, - getFieldCounts + services.uiSettings ); services.share.toggleShareContextMenu({ anchorElement, diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts index 5e0e48e619a27..d3a23fa6a939a 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts @@ -16,54 +16,26 @@ import { SORT_DEFAULT_ORDER_SETTING } from '../../../common'; describe('getSharingData', () => { test('returns valid data for sharing', async () => { const searchSourceMock = createSearchSourceMock({ index: indexPatternMock }); - const result = await getSharingData( - searchSourceMock, - { columns: [] }, - ({ - get: (key: string) => { - if (key === SORT_DEFAULT_ORDER_SETTING) { - return 'desc'; - } - return false; - }, - } as unknown) as IUiSettingsClient, - () => Promise.resolve({}) - ); + const result = await getSharingData(searchSourceMock, { columns: [] }, ({ + get: (key: string) => { + if (key === SORT_DEFAULT_ORDER_SETTING) { + return 'desc'; + } + return false; + }, + } as unknown) as IUiSettingsClient); expect(result).toMatchInlineSnapshot(` Object { - "conflictedTypesFields": Array [], - "fields": Array [], - "indexPatternId": "the-index-pattern-id", - "metaFields": Array [ - "_index", - "_score", - ], - "searchRequest": Object { - "body": Object { - "_source": Object {}, - "fields": Array [], - "query": Object { - "bool": Object { - "filter": Array [], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, + "searchSource": Object { + "fields": Array [ + "*", + ], + "index": "the-index-pattern-id", + "sort": Array [ + Object { + "_score": "desc", }, - "runtime_mappings": Object {}, - "script_fields": Object {}, - "sort": Array [ - Object { - "_score": Object { - "order": "desc", - }, - }, - ], - "stored_fields": Array [ - "*", - ], - }, - "index": "the-index-pattern-title", + ], }, } `); diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 2455589cf69fc..11b2309df305e 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -6,57 +6,24 @@ * Side Public License, v 1. */ -import { Capabilities, IUiSettingsClient } from 'kibana/public'; +import type { Capabilities, IUiSettingsClient } from 'kibana/public'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../common'; import { getSortForSearchSource } from '../angular/doc_table'; import { ISearchSource } from '../../../../data/common'; import { AppState } from '../angular/discover_state'; -import { SortOrder } from '../../saved_searches/types'; - -const getSharingDataFields = async ( - getFieldCounts: () => Promise>, - selectedFields: string[], - timeFieldName: string, - hideTimeColumn: boolean -) => { - if ( - selectedFields.length === 0 || - (selectedFields.length === 1 && selectedFields[0] === '_source') - ) { - const fieldCounts = await getFieldCounts(); - return { - searchFields: undefined, - selectFields: Object.keys(fieldCounts).sort(), - }; - } - - const fields = - timeFieldName && !hideTimeColumn ? [timeFieldName, ...selectedFields] : selectedFields; - return { - searchFields: fields, - selectFields: fields, - }; -}; +import { SavedSearch, SortOrder } from '../../saved_searches/types'; /** * Preparing data to share the current state as link or CSV/Report */ export async function getSharingData( currentSearchSource: ISearchSource, - state: AppState, - config: IUiSettingsClient, - getFieldCounts: () => Promise> + state: AppState | SavedSearch, + config: IUiSettingsClient ) { const searchSource = currentSearchSource.createCopy(); const index = searchSource.getField('index')!; - const { searchFields, selectFields } = await getSharingDataFields( - getFieldCounts, - state.columns || [], - index.timeFieldName || '', - config.get(DOC_HIDE_TIME_COLUMN_SETTING) - ); - searchSource.setField('fieldsFromSource', searchFields); searchSource.setField( 'sort', getSortForSearchSource(state.sort as SortOrder[], index, config.get(SORT_DEFAULT_ORDER_SETTING)) @@ -66,20 +33,45 @@ export async function getSharingData( searchSource.removeField('aggs'); searchSource.removeField('size'); - const body = await searchSource.getSearchRequestBody(); + // Set the fields of the search source to match the saved search columns + searchSource.removeField('fields'); + searchSource.removeField('fieldsFromSource'); + + let columns = state.columns || []; + + // NOTE: A newly saved search with no columns selected has a bug(?) where the + // column array is a single '_source' value which is invalid for CSV export + if (columns && columns.length === 1 && /^_source$/.test(columns.join())) { + columns = []; + } + + // conditionally add the time field column + let timeFieldName: string | undefined; + const hideTimeColumn = config.get(DOC_HIDE_TIME_COLUMN_SETTING); + if (!hideTimeColumn && index && index.timeFieldName) { + timeFieldName = index.timeFieldName; + } + + if (columns && columns.length > 0 && timeFieldName) { + columns = [timeFieldName, ...columns]; + } + + if (columns.length === 0) { + searchSource.setField('fields', ['*']); + } else { + searchSource.setField('fields', columns); + } return { - searchRequest: { - index: index.title, - body, - }, - fields: selectFields, - metaFields: index.metaFields, - conflictedTypesFields: index.fields.filter((f) => f.type === 'conflict').map((f) => f.name), - indexPatternId: index.id, + searchSource: searchSource.getSerializedFields(true), }; } +/** + * makes getSharingData lazy loadable + */ +export function getSharingDataModule() {} + export interface DiscoverCapabilities { createShortUrl?: boolean; save?: boolean; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index de76c65ccdc98..fbe853ec6deb5 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -16,4 +16,5 @@ export function plugin(initializerContext: PluginInitializerContext) { export { SavedSearch, SavedSearchLoader, createSavedSearchesLoader } from './saved_searches'; export { ISearchEmbeddable, SEARCH_EMBEDDABLE_TYPE, SearchInput } from './application/embeddable'; +export { loadSharingDataHelpers } from './shared'; export { DISCOVER_APP_URL_GENERATOR, DiscoverUrlGeneratorState } from './url_generator'; diff --git a/src/plugins/discover/public/shared/index.ts b/src/plugins/discover/public/shared/index.ts new file mode 100644 index 0000000000000..b1e4d9d87000e --- /dev/null +++ b/src/plugins/discover/public/shared/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* + * Allows the getSharingData function to be lazy loadable + */ +export async function loadSharingDataHelpers() { + return await import('../application/helpers/get_sharing_data'); +} diff --git a/x-pack/plugins/reporting/common/constants.ts b/x-pack/plugins/reporting/common/constants.ts index e3f58dd20cecb..2a95557473fc0 100644 --- a/x-pack/plugins/reporting/common/constants.ts +++ b/x-pack/plugins/reporting/common/constants.ts @@ -50,6 +50,7 @@ export const KBN_SCREENSHOT_HEADER_BLOCK_LIST_STARTS_WITH_PATTERN = ['proxy-']; export const UI_SETTINGS_CUSTOM_PDF_LOGO = 'xpackReporting:customPdfLogo'; export const UI_SETTINGS_CSV_SEPARATOR = 'csv:separator'; export const UI_SETTINGS_CSV_QUOTE_VALUES = 'csv:quoteValues'; +export const UI_SETTINGS_DATEFORMAT_TZ = 'dateFormat:tz'; export const LAYOUT_TYPES = { PRESERVE_LAYOUT: 'preserve_layout', @@ -57,13 +58,16 @@ export const LAYOUT_TYPES = { }; // Export Type Definitions +export const CSV_REPORT_TYPE = 'CSV'; +export const CSV_JOB_TYPE = 'csv_searchsource'; + export const PDF_REPORT_TYPE = 'printablePdf'; export const PDF_JOB_TYPE = 'printable_pdf'; export const PNG_REPORT_TYPE = 'PNG'; export const PNG_JOB_TYPE = 'PNG'; -export const CSV_FROM_SAVEDOBJECT_JOB_TYPE = 'csv_from_savedobject'; +export const CSV_SEARCHSOURCE_IMMEDIATE_TYPE = 'csv_searchsource_immediate'; // This is deprecated because it lacks support for runtime fields // but the extension points are still needed for pre-existing scripted automation, until 8.0 @@ -86,9 +90,9 @@ export const API_BASE_GENERATE = `${API_BASE_URL}/generate`; export const API_LIST_URL = `${API_BASE_URL}/jobs`; export const API_DIAGNOSE_URL = `${API_BASE_URL}/diagnose`; -// hacky endpoint +// hacky endpoint: download CSV without queueing a report export const API_BASE_URL_V1 = '/api/reporting/v1'; // -export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv/saved-object`; +export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv_searchsource`; // Management UI route export const REPORTING_MANAGEMENT_HOME = '/app/management/insightsAndAlerting/reporting'; diff --git a/x-pack/plugins/reporting/common/types.ts b/x-pack/plugins/reporting/common/types.ts index 3af329cbf0303..5e20381e35898 100644 --- a/x-pack/plugins/reporting/common/types.ts +++ b/x-pack/plugins/reporting/common/types.ts @@ -47,9 +47,10 @@ export interface ReportDocumentHead { export interface TaskRunResult { content_type: string | null; content: string | null; - csv_contains_formulas?: boolean; size: number; + csv_contains_formulas?: boolean; max_size_reached?: boolean; + needs_sorting?: boolean; warnings?: string[]; } diff --git a/x-pack/plugins/reporting/public/components/reporting_panel_content.tsx b/x-pack/plugins/reporting/public/components/reporting_panel_content.tsx index 6673aded2ecbe..db9ddec90b605 100644 --- a/x-pack/plugins/reporting/public/components/reporting_panel_content.tsx +++ b/x-pack/plugins/reporting/public/components/reporting_panel_content.tsx @@ -11,11 +11,7 @@ import React, { Component, ReactElement } from 'react'; import { ToastsSetup } from 'src/core/public'; import url from 'url'; import { toMountPoint } from '../../../../../src/plugins/kibana_react/public'; -import { - CSV_REPORT_TYPE_DEPRECATED, - PDF_REPORT_TYPE, - PNG_REPORT_TYPE, -} from '../../common/constants'; +import { CSV_REPORT_TYPE, PDF_REPORT_TYPE, PNG_REPORT_TYPE } from '../../common/constants'; import { BaseParams } from '../../common/types'; import { ReportingAPIClient } from '../lib/reporting_api_client'; @@ -177,8 +173,8 @@ class ReportingPanelContentUi extends Component { switch (this.props.reportType) { case PDF_REPORT_TYPE: return 'PDF'; - case 'csv': - return CSV_REPORT_TYPE_DEPRECATED; + case 'csv_searchsource': + return CSV_REPORT_TYPE; case 'png': return PNG_REPORT_TYPE; default: diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts index f452719e91713..4e1b9ccd2642f 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts @@ -52,7 +52,20 @@ describe('GetCsvReportPanelAction', () => { context = { embeddable: { type: 'search', - getSavedSearch: () => ({ id: 'lebowski' }), + getSavedSearch: () => { + const searchSource = { + createCopy: () => searchSource, + removeField: jest.fn(), + setField: jest.fn(), + getField: jest.fn().mockImplementation((key: string) => { + if (key === 'index') { + return 'my-test-index-*'; + } + }), + getSerializedFields: jest.fn().mockImplementation(() => ({})), + }; + return { searchSource }; + }, getTitle: () => `The Dude`, getInspectorAdapters: () => null, getInput: () => ({ diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx index cc1da146eff32..d440edc3f3fe9 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx @@ -5,13 +5,13 @@ * 2.0. */ -import dateMath from '@elastic/datemath'; import { i18n } from '@kbn/i18n'; -import _ from 'lodash'; import moment from 'moment-timezone'; import { CoreSetup } from 'src/core/public'; import { + loadSharingDataHelpers, ISearchEmbeddable, + SavedSearch, SEARCH_EMBEDDABLE_TYPE, } from '../../../../../src/plugins/discover/public'; import { IEmbeddable, ViewMode } from '../../../../../src/plugins/embeddable/public'; @@ -21,6 +21,7 @@ import { } from '../../../../../src/plugins/ui_actions/public'; import { LicensingPluginSetup } from '../../../licensing/public'; import { API_GENERATE_IMMEDIATE, CSV_REPORTING_ACTION } from '../../common/constants'; +import { JobParamsDownloadCSV } from '../../server/export_types/csv_searchsource_immediate/types'; import { checkLicense } from '../lib/license_check'; function isSavedSearchEmbeddable( @@ -61,17 +62,16 @@ export class GetCsvReportPanelAction implements ActionDefinition }); } - public getSearchRequestBody({ searchEmbeddable }: { searchEmbeddable: any }) { - const adapters = searchEmbeddable.getInspectorAdapters(); - if (!adapters) { - return {}; - } - - if (adapters.requests.requests.length === 0) { - return {}; - } + public async getSearchSource(savedSearch: SavedSearch, embeddable: ISearchEmbeddable) { + const { getSharingData } = await loadSharingDataHelpers(); + const searchSource = savedSearch.searchSource.createCopy(); + const { searchSource: serializedSearchSource } = await getSharingData( + searchSource, + savedSearch, // TODO: get unsaved state (using embeddale.searchScope): https://github.com/elastic/kibana/issues/43977 + this.core.uiSettings + ); - return searchEmbeddable.getSavedSearch().searchSource.getSearchRequestBody(); + return serializedSearchSource; } public isCompatible = async (context: ActionContext) => { @@ -95,34 +95,18 @@ export class GetCsvReportPanelAction implements ActionDefinition return; } - const { - timeRange: { to, from }, - } = embeddable.getInput(); + const savedSearch = embeddable.getSavedSearch(); + const searchSource = await this.getSearchSource(savedSearch, embeddable); - const searchEmbeddable = embeddable; - const searchRequestBody = await this.getSearchRequestBody({ searchEmbeddable }); - const state = _.pick(searchRequestBody, ['sort', 'docvalue_fields', 'query']); const kibanaTimezone = this.core.uiSettings.get('dateFormat:tz'); + const browserTimezone = kibanaTimezone === 'Browser' ? moment.tz.guess() : kibanaTimezone; + const immediateJobParams: JobParamsDownloadCSV = { + searchSource, + browserTimezone, + title: savedSearch.title, + }; - const id = `search:${embeddable.getSavedSearch().id}`; - const timezone = kibanaTimezone === 'Browser' ? moment.tz.guess() : kibanaTimezone; - const fromTime = dateMath.parse(from); - const toTime = dateMath.parse(to, { roundUp: true }); - - if (!fromTime || !toTime) { - return this.onGenerationFail( - new Error(`Invalid time range: From: ${fromTime}, To: ${toTime}`) - ); - } - - const body = JSON.stringify({ - timerange: { - min: fromTime.format(), - max: toTime.format(), - timezone, - }, - state, - }); + const body = JSON.stringify(immediateJobParams); this.isDownloading = true; @@ -137,11 +121,11 @@ export class GetCsvReportPanelAction implements ActionDefinition }); await this.core.http - .post(`${API_GENERATE_IMMEDIATE}/${id}`, { body }) + .post(`${API_GENERATE_IMMEDIATE}`, { body }) .then((rawResponse: string) => { this.isDownloading = false; - const download = `${embeddable.getSavedSearch().title}.csv`; + const download = `${savedSearch.title}.csv`; const blob = new Blob([rawResponse], { type: 'text/csv;charset=utf-8;' }); // Hack for IE11 Support diff --git a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx index 31c86ae4c5669..97433f7a4f0c1 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx @@ -11,10 +11,8 @@ import React from 'react'; import { IUiSettingsClient, ToastsSetup } from 'src/core/public'; import { ShareContext } from '../../../../../src/plugins/share/public'; import { LicensingPluginSetup } from '../../../licensing/public'; -import { - JobParamsDeprecatedCSV, - SearchRequestDeprecatedCSV, -} from '../../server/export_types/csv/types'; +import { CSV_JOB_TYPE } from '../../common/constants'; +import { JobParamsCSV } from '../../server/export_types/csv_searchsource/types'; import { ReportingPanelContent } from '../components/reporting_panel_content_lazy'; import { checkLicense } from '../lib/license_check'; import { ReportingAPIClient } from '../lib/reporting_api_client'; @@ -56,22 +54,18 @@ export const csvReportingProvider = ({ objectType, objectId, sharingData, - isDirty, onClose, + isDirty, }: ShareContext) => { if ('search' !== objectType) { return []; } - const jobParams: JobParamsDeprecatedCSV = { + const jobParams: JobParamsCSV = { browserTimezone, - objectType, title: sharingData.title as string, - indexPatternId: sharingData.indexPatternId as string, - searchRequest: sharingData.searchRequest as SearchRequestDeprecatedCSV, - fields: sharingData.fields as string[], - metaFields: sharingData.metaFields as string[], - conflictedTypesFields: sharingData.conflictedTypesFields as string[], + objectType, + searchSource: sharingData.searchSource, }; const getJobParams = () => jobParams; @@ -99,7 +93,7 @@ export const csvReportingProvider = ({ ; @@ -45,6 +47,8 @@ export interface ReportingInternalStart { store: ReportingStore; savedObjects: SavedObjectsServiceStart; uiSettings: UiSettingsServiceStart; + esClient: IClusterClient; + data: DataPluginStart; } export class ReportingCore { @@ -239,4 +243,14 @@ export class ReportingCore { const savedObjectsClient = await this.getSavedObjectsClient(request); return await this.getUiSettingsServiceFactory(savedObjectsClient); } + + public async getSearchService() { + const startDeps = await this.getPluginStartDeps(); + return startDeps.data.search; + } + + public async getEsClient() { + const startDeps = await this.getPluginStartDeps(); + return startDeps.esClient; + } } diff --git a/x-pack/plugins/reporting/server/export_types/common/index.ts b/x-pack/plugins/reporting/server/export_types/common/index.ts index 1003ecf83601c..8832577281bb2 100644 --- a/x-pack/plugins/reporting/server/export_types/common/index.ts +++ b/x-pack/plugins/reporting/server/export_types/common/index.ts @@ -12,7 +12,6 @@ export { omitBlockedHeaders } from './omit_blocked_headers'; export { validateUrls } from './validate_urls'; export interface TimeRangeParams { - timezone: string; min?: Date | string | number | null; max?: Date | string | number | null; } diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts index 942739f0d9945..c2114bc6bcd1e 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { pick, keys, values, some } from 'lodash'; -import { cellHasFormulas } from './cell_has_formula'; +import { keys, pick, some, values } from 'lodash'; +import { cellHasFormulas } from '../../csv_searchsource/generate_csv/cell_has_formula'; interface IFlattened { [header: string]: string; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts index ed05180501e32..629a81df350be 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts @@ -13,15 +13,18 @@ import { CSV_BOM_CHARS } from '../../../../common/constants'; import { byteSizeValueToNumber } from '../../../../common/schema_utils'; import { LevelLogger } from '../../../lib'; import { getFieldFormats } from '../../../services'; -import { IndexPatternSavedObjectDeprecatedCSV, SavedSearchGeneratorResult } from '../types'; +import { createEscapeValue } from '../../csv_searchsource/generate_csv/escape_value'; +import { MaxSizeStringBuilder } from '../../csv_searchsource/generate_csv/max_size_string_builder'; +import { + IndexPatternSavedObjectDeprecatedCSV, + SavedSearchGeneratorResultDeprecatedCSV, +} from '../types'; import { checkIfRowsHaveFormulas } from './check_cells_for_formulas'; -import { createEscapeValue } from './escape_value'; import { fieldFormatMapFactory } from './field_format_map'; import { createFlattenHit } from './flatten_hit'; import { createFormatCsvValues } from './format_csv_values'; import { getUiSettings } from './get_ui_settings'; import { createHitIterator, EndpointCaller } from './hit_iterator'; -import { MaxSizeStringBuilder } from './max_size_string_builder'; interface SearchRequest { index: string; @@ -55,7 +58,7 @@ export function createGenerateCsv(logger: LevelLogger) { uiSettingsClient: IUiSettingsClient, callEndpoint: EndpointCaller, cancellationToken: CancellationToken - ): Promise { + ): Promise { const settings = await getUiSettings(job.browserTimezone, uiSettingsClient, config, logger); const escapeValue = createEscapeValue(settings.quoteValues, settings.escapeFormulaValues); const bom = config.get('csv', 'useByteOrderMarkEncoding') ? CSV_BOM_CHARS : ''; diff --git a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts index 4c4f33d0ee9f7..604d451d822b6 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts @@ -77,15 +77,10 @@ type FormatsMapDeprecatedCSV = Map< } >; -export interface SavedSearchGeneratorResult { +export interface SavedSearchGeneratorResultDeprecatedCSV { content: string; size: number; maxSizeReached: boolean; csvContainsFormulas?: boolean; warnings: string[]; } - -export interface CsvResultFromSearch { - type: string; - result: SavedSearchGeneratorResult; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/create_job.ts deleted file mode 100644 index b27c244aa11ae..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/create_job.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { notFound, notImplemented } from '@hapi/boom'; -import { get } from 'lodash'; -import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; -import { CsvFromSavedObjectRequest } from '../../routes/generate_from_savedobject_immediate'; -import { CreateJobFnFactory } from '../../types'; -import { - JobParamsPanelCsv, - JobPayloadPanelCsv, - SavedObject, - SavedObjectReference, - SavedObjectServiceError, - VisObjectAttributesJSON, -} from './types'; -import type { ReportingRequestHandlerContext } from '../../types'; - -export type ImmediateCreateJobFn = ( - jobParams: JobParamsPanelCsv, - context: ReportingRequestHandlerContext, - req: CsvFromSavedObjectRequest -) => Promise; - -export const createJobFnFactory: CreateJobFnFactory = function createJobFactoryFn( - reporting, - parentLogger -) { - const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'create-job']); - - return async function createJob(jobParams, context, req) { - const { savedObjectType, savedObjectId } = jobParams; - - const panel = await Promise.resolve() - .then(() => context.core.savedObjects.client.get(savedObjectType, savedObjectId)) - .then(async (savedObject: SavedObject) => { - const { attributes, references } = savedObject; - const { kibanaSavedObjectMeta: kibanaSavedObjectMetaJSON } = attributes; - const { timerange } = req.body; - - if (!kibanaSavedObjectMetaJSON) { - throw new Error('Could not parse saved object data!'); - } - - const kibanaSavedObjectMeta = { - ...kibanaSavedObjectMetaJSON, - searchSource: JSON.parse(kibanaSavedObjectMetaJSON.searchSourceJSON), - }; - - const { visState: visStateJSON } = attributes as VisObjectAttributesJSON; - if (visStateJSON) { - throw notImplemented('Visualization types are not yet implemented'); - } - - // saved search type - const { searchSource } = kibanaSavedObjectMeta; - if (!searchSource || !references) { - throw new Error('The saved search object is missing configuration fields!'); - } - - const indexPatternMeta = references.find( - (ref: SavedObjectReference) => ref.type === 'index-pattern' - ); - if (!indexPatternMeta) { - throw new Error('Could not find index pattern for the saved search!'); - } - - return { - attributes: { - ...attributes, - kibanaSavedObjectMeta: { searchSource }, - }, - indexPatternSavedObjectId: indexPatternMeta.id, - timerange, - }; - }) - .catch((err: Error) => { - const boomErr = (err as unknown) as { isBoom: boolean }; - if (boomErr.isBoom) { - throw err; - } - const errPayload: SavedObjectServiceError = get(err, 'output.payload', { statusCode: 0 }); - if (errPayload.statusCode === 404) { - throw notFound(errPayload.message); - } - logger.error(err); - throw new Error(`Unable to create a job from saved object data! Error: ${err}`); - }); - - return { ...jobParams, panel }; - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts deleted file mode 100644 index b037e72699dd6..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaRequest } from 'src/core/server'; -import { CancellationToken } from '../../../common'; -import { CONTENT_TYPE_CSV, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; -import { TaskRunResult } from '../../lib/tasks'; -import { RunTaskFnFactory } from '../../types'; -import { createGenerateCsv } from '../csv/generate_csv'; -import { getGenerateCsvParams } from './lib/get_csv_job'; -import { JobPayloadPanelCsv } from './types'; -import type { ReportingRequestHandlerContext } from '../../types'; - -/* - * ImmediateExecuteFn receives the job doc payload because the payload was - * generated in the ScheduleFn - */ -export type ImmediateExecuteFn = ( - jobId: null, - job: JobPayloadPanelCsv, - context: ReportingRequestHandlerContext, - req: KibanaRequest -) => Promise; - -export const runTaskFnFactory: RunTaskFnFactory = function executeJobFactoryFn( - reporting, - parentLogger -) { - const config = reporting.getConfig(); - const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'execute-job']); - - return async function runTask(jobId, jobPayload, context, req) { - const generateCsv = createGenerateCsv(logger); - const { panel } = jobPayload; - - logger.debug(`Execute job generating saved search CSV`); - - const savedObjectsClient = context.core.savedObjects.client; - const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); - const job = await getGenerateCsvParams( - jobPayload, - panel, - savedObjectsClient, - uiSettingsClient, - logger - ); - - const elasticsearch = reporting.getElasticsearchService(); - const { callAsCurrentUser } = elasticsearch.legacy.client.asScoped(req); - - const { content, maxSizeReached, size, csvContainsFormulas, warnings } = await generateCsv( - job, - config, - uiSettingsClient, - callAsCurrentUser, - new CancellationToken() // can not be cancelled - ); - - if (csvContainsFormulas) { - logger.warn(`CSV may contain formulas whose values have been escaped`); - } - - if (maxSizeReached) { - logger.warn(`Max size reached: CSV output truncated to ${size} bytes`); - } - - return { - content_type: CONTENT_TYPE_CSV, - content, - max_size_reached: maxSizeReached, - size, - csv_contains_formulas: csvContainsFormulas, - warnings, - }; - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.test.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.test.ts deleted file mode 100644 index fc6e092962d3b..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.test.ts +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createMockLevelLogger } from '../../../test_helpers'; -import { JobParamsPanelCsv, SearchPanel } from '../types'; -import { getGenerateCsvParams } from './get_csv_job'; - -const logger = createMockLevelLogger(); - -describe('Get CSV Job', () => { - let mockJobParams: JobParamsPanelCsv; - let mockSearchPanel: SearchPanel; - let mockSavedObjectsClient: any; - let mockUiSettingsClient: any; - beforeEach(() => { - mockJobParams = { savedObjectType: 'search', savedObjectId: '234-ididid' }; - mockSearchPanel = { - indexPatternSavedObjectId: '123-indexId', - attributes: { - title: 'my search', - sort: [], - kibanaSavedObjectMeta: { - searchSource: { query: { isSearchSourceQuery: true }, filter: [] }, - }, - uiState: 56, - }, - timerange: { timezone: 'PST', min: 0, max: 100 }, - }; - mockSavedObjectsClient = { - get: () => ({ - attributes: { fields: null, title: null, timeFieldName: null }, - }), - }; - mockUiSettingsClient = { - get: () => ({}), - }; - }); - - it('creates a data structure needed by generateCsv', async () => { - const result = await getGenerateCsvParams( - mockJobParams, - mockSearchPanel, - mockSavedObjectsClient, - mockUiSettingsClient, - logger - ); - expect(result).toMatchInlineSnapshot(` - Object { - "browserTimezone": "PST", - "conflictedTypesFields": Array [], - "fields": Array [], - "indexPatternSavedObject": Object { - "attributes": Object { - "fields": null, - "timeFieldName": null, - "title": null, - }, - "fields": Array [], - "timeFieldName": null, - "title": null, - }, - "metaFields": Array [], - "searchRequest": Object { - "body": Object { - "_source": Object { - "includes": Array [], - }, - "docvalue_fields": undefined, - "query": Object { - "bool": Object { - "filter": Array [], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, - }, - "script_fields": Object {}, - "sort": Array [], - }, - "index": null, - }, - } - `); - }); - - it('uses query and sort from the payload', async () => { - mockJobParams.post = { - state: { - query: ['this is the query'], - sort: ['this is the sort'], - }, - }; - const result = await getGenerateCsvParams( - mockJobParams, - mockSearchPanel, - mockSavedObjectsClient, - mockUiSettingsClient, - logger - ); - expect(result).toMatchInlineSnapshot(` - Object { - "browserTimezone": "PST", - "conflictedTypesFields": Array [], - "fields": Array [], - "indexPatternSavedObject": Object { - "attributes": Object { - "fields": null, - "timeFieldName": null, - "title": null, - }, - "fields": Array [], - "timeFieldName": null, - "title": null, - }, - "metaFields": Array [], - "searchRequest": Object { - "body": Object { - "_source": Object { - "includes": Array [], - }, - "docvalue_fields": undefined, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "0": "this is the query", - }, - ], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, - }, - "script_fields": Object {}, - "sort": Array [ - "this is the sort", - ], - }, - "index": null, - }, - } - `); - }); - - it('uses timerange timezone from the payload', async () => { - mockJobParams.post = { - timerange: { timezone: 'Africa/Timbuktu', min: 0, max: 9000 }, - }; - const result = await getGenerateCsvParams( - mockJobParams, - mockSearchPanel, - mockSavedObjectsClient, - mockUiSettingsClient, - logger - ); - expect(result).toMatchInlineSnapshot(` - Object { - "browserTimezone": "Africa/Timbuktu", - "conflictedTypesFields": Array [], - "fields": Array [], - "indexPatternSavedObject": Object { - "attributes": Object { - "fields": null, - "timeFieldName": null, - "title": null, - }, - "fields": Array [], - "timeFieldName": null, - "title": null, - }, - "metaFields": Array [], - "searchRequest": Object { - "body": Object { - "_source": Object { - "includes": Array [], - }, - "docvalue_fields": undefined, - "query": Object { - "bool": Object { - "filter": Array [], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, - }, - "script_fields": Object {}, - "sort": Array [], - }, - "index": null, - }, - } - `); - }); - - it('uses timerange min and max (numeric) when index pattern has timefieldName', async () => { - mockJobParams.post = { - timerange: { timezone: 'Africa/Timbuktu', min: 0, max: 900000000 }, - }; - mockSavedObjectsClient = { - get: () => ({ - attributes: { fields: null, title: 'test search', timeFieldName: '@test_time' }, - }), - }; - const result = await getGenerateCsvParams( - mockJobParams, - mockSearchPanel, - mockSavedObjectsClient, - mockUiSettingsClient, - logger - ); - expect(result).toMatchInlineSnapshot(` - Object { - "browserTimezone": "Africa/Timbuktu", - "conflictedTypesFields": Array [], - "fields": Array [ - "@test_time", - ], - "indexPatternSavedObject": Object { - "attributes": Object { - "fields": null, - "timeFieldName": "@test_time", - "title": "test search", - }, - "fields": Array [], - "timeFieldName": "@test_time", - "title": "test search", - }, - "metaFields": Array [], - "searchRequest": Object { - "body": Object { - "_source": Object { - "includes": Array [ - "@test_time", - ], - }, - "docvalue_fields": undefined, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "range": Object { - "@test_time": Object { - "format": "strict_date_time", - "gte": "1970-01-01T00:00:00Z", - "lte": "1970-01-11T10:00:00Z", - }, - }, - }, - ], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, - }, - "script_fields": Object {}, - "sort": Array [], - }, - "index": "test search", - }, - } - `); - }); - - it('uses timerange min and max (string) when index pattern has timefieldName', async () => { - mockJobParams.post = { - timerange: { - timezone: 'Africa/Timbuktu', - min: '1980-01-01T00:00:00Z', - max: '1990-01-01T00:00:00Z', - }, - }; - mockSavedObjectsClient = { - get: () => ({ - attributes: { fields: null, title: 'test search', timeFieldName: '@test_time' }, - }), - }; - const result = await getGenerateCsvParams( - mockJobParams, - mockSearchPanel, - mockSavedObjectsClient, - mockUiSettingsClient, - logger - ); - expect(result).toMatchInlineSnapshot(` - Object { - "browserTimezone": "Africa/Timbuktu", - "conflictedTypesFields": Array [], - "fields": Array [ - "@test_time", - ], - "indexPatternSavedObject": Object { - "attributes": Object { - "fields": null, - "timeFieldName": "@test_time", - "title": "test search", - }, - "fields": Array [], - "timeFieldName": "@test_time", - "title": "test search", - }, - "metaFields": Array [], - "searchRequest": Object { - "body": Object { - "_source": Object { - "includes": Array [ - "@test_time", - ], - }, - "docvalue_fields": undefined, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "range": Object { - "@test_time": Object { - "format": "strict_date_time", - "gte": "1980-01-01T00:00:00Z", - "lte": "1990-01-01T00:00:00Z", - }, - }, - }, - ], - "must": Array [], - "must_not": Array [], - "should": Array [], - }, - }, - "script_fields": Object {}, - "sort": Array [], - }, - "index": "test search", - }, - } - `); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.ts deleted file mode 100644 index e4570816e26ff..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_csv_job.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IUiSettingsClient, SavedObjectsClientContract } from 'kibana/server'; -import { EsQueryConfig } from 'src/plugins/data/server'; -import { esQuery, Filter, Query } from '../../../../../../../src/plugins/data/server'; -import { LevelLogger } from '../../../lib'; -import { TimeRangeParams } from '../../common'; -import { GenerateCsvParams } from '../../csv/generate_csv'; -import { - DocValueFields, - IndexPatternField, - JobParamsPanelCsv, - QueryFilter, - SavedSearchObjectAttributes, - SearchPanel, - SearchSource, -} from '../types'; -import { getDataSource } from './get_data_source'; -import { getFilters } from './get_filters'; - -export const getEsQueryConfig = async (config: IUiSettingsClient) => { - const configs = await Promise.all([ - config.get('query:allowLeadingWildcards'), - config.get('query:queryString:options'), - config.get('courier:ignoreFilterIfFieldNotInIndex'), - ]); - const [allowLeadingWildcards, queryStringOptions, ignoreFilterIfFieldNotInIndex] = configs; - return { - allowLeadingWildcards, - queryStringOptions, - ignoreFilterIfFieldNotInIndex, - } as EsQueryConfig; -}; - -/* - * Create a CSV Job object for CSV From SavedObject to use as a job parameter - * for generateCsv - */ -export const getGenerateCsvParams = async ( - jobParams: JobParamsPanelCsv, - panel: SearchPanel, - savedObjectsClient: SavedObjectsClientContract, - uiConfig: IUiSettingsClient, - logger: LevelLogger -): Promise => { - let timerange: TimeRangeParams | null; - if (jobParams.post?.timerange) { - timerange = jobParams.post?.timerange; - } else { - timerange = panel.timerange || null; - } - const { indexPatternSavedObjectId } = panel; - const savedSearchObjectAttr = panel.attributes as SavedSearchObjectAttributes; - const { indexPatternSavedObject } = await getDataSource( - savedObjectsClient, - indexPatternSavedObjectId - ); - const esQueryConfig = await getEsQueryConfig(uiConfig); - - const { - kibanaSavedObjectMeta: { - searchSource: { - filter: [searchSourceFilter], - query: searchSourceQuery, - }, - }, - } = savedSearchObjectAttr as { kibanaSavedObjectMeta: { searchSource: SearchSource } }; - - const { - timeFieldName: indexPatternTimeField, - title: esIndex, - fields: indexPatternFields, - } = indexPatternSavedObject; - - if (!indexPatternFields || indexPatternFields.length === 0) { - logger.error( - new Error( - `No fields are selected in the saved search! Please select fields as columns in the saved search and try again.` - ) - ); - } - - let payloadQuery: QueryFilter | undefined; - let payloadSort: any[] = []; - let docValueFields: DocValueFields[] | undefined; - if (jobParams.post && jobParams.post.state) { - ({ - post: { - state: { query: payloadQuery, sort: payloadSort = [], docvalue_fields: docValueFields }, - }, - } = jobParams); - } - const { includes, combinedFilter } = getFilters( - indexPatternSavedObjectId, - indexPatternTimeField, - timerange, - savedSearchObjectAttr, - searchSourceFilter, - payloadQuery - ); - - const savedSortConfigs = savedSearchObjectAttr.sort; - const sortConfig = [...payloadSort]; - savedSortConfigs.forEach(([savedSortField, savedSortOrder]) => { - sortConfig.push({ [savedSortField]: { order: savedSortOrder } }); - }); - - const scriptFieldsConfig = - indexPatternFields && - indexPatternFields - .filter((f: IndexPatternField) => f.scripted) - .reduce((accum: any, curr: IndexPatternField) => { - return { - ...accum, - [curr.name]: { - script: { - source: curr.script, - lang: curr.lang, - }, - }, - }; - }, {}); - - const searchRequest = { - index: esIndex, - body: { - _source: { includes }, - docvalue_fields: docValueFields, - query: esQuery.buildEsQuery( - // compromise made while factoring out IIndexPattern type - // @ts-expect-error - indexPatternSavedObject, - (searchSourceQuery as unknown) as Query, - (combinedFilter as unknown) as Filter, - esQueryConfig - ), - script_fields: scriptFieldsConfig, - sort: sortConfig, - }, - }; - - return { - browserTimezone: timerange?.timezone, - indexPatternSavedObject, - searchRequest, - fields: includes, - metaFields: [], - conflictedTypesFields: [], - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_data_source.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_data_source.ts deleted file mode 100644 index d903a1d8ba9e8..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_data_source.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IndexPatternSavedObjectDeprecatedCSV } from '../../csv/types'; -import { SavedObjectReference, SavedSearchObjectAttributesJSON, SearchSource } from '../types'; - -export async function getDataSource( - savedObjectsClient: any, - indexPatternId?: string, - savedSearchObjectId?: string -): Promise<{ - indexPatternSavedObject: IndexPatternSavedObjectDeprecatedCSV; - searchSource: SearchSource | null; -}> { - let indexPatternSavedObject: IndexPatternSavedObjectDeprecatedCSV; - let searchSource: SearchSource | null = null; - - if (savedSearchObjectId) { - try { - const { attributes, references } = (await savedObjectsClient.get( - 'search', - savedSearchObjectId - )) as { attributes: SavedSearchObjectAttributesJSON; references: SavedObjectReference[] }; - searchSource = JSON.parse(attributes.kibanaSavedObjectMeta.searchSourceJSON); - const { id: indexPatternFromSearchId } = references.find( - ({ type }) => type === 'index-pattern' - ) as { id: string }; - ({ indexPatternSavedObject } = await getDataSource( - savedObjectsClient, - indexPatternFromSearchId - )); - return { searchSource, indexPatternSavedObject }; - } catch (err) { - throw new Error(`Could not get saved search info! ${err}`); - } - } - try { - const { attributes } = await savedObjectsClient.get('index-pattern', indexPatternId); - const { fields, title, timeFieldName } = attributes; - const parsedFields = fields ? JSON.parse(fields) : []; - - indexPatternSavedObject = { - fields: parsedFields, - title, - timeFieldName, - attributes, - }; - } catch (err) { - throw new Error(`Could not get index pattern saved object! ${err}`); - } - return { indexPatternSavedObject, searchSource }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.test.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.test.ts deleted file mode 100644 index ca5bf12e1d510..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.test.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { TimeRangeParams } from '../../common'; -import { QueryFilter, SavedSearchObjectAttributes, SearchSourceFilter } from '../types'; -import { getFilters } from './get_filters'; - -interface Args { - indexPatternId: string; - indexPatternTimeField: string | null; - timerange: TimeRangeParams | null; - savedSearchObjectAttr: SavedSearchObjectAttributes; - searchSourceFilter: SearchSourceFilter; - queryFilter: QueryFilter; -} - -describe('CSV from Saved Object: get_filters', () => { - let args: Args; - beforeEach(() => { - args = { - indexPatternId: 'logs-test-*', - indexPatternTimeField: 'testtimestamp', - timerange: { - timezone: 'UTC', - min: '1901-01-01T00:00:00.000Z', - max: '1902-01-01T00:00:00.000Z', - }, - savedSearchObjectAttr: { - title: 'test', - sort: [{ sortField: { order: 'asc' } }], - kibanaSavedObjectMeta: { - searchSource: { - query: { isSearchSourceQuery: true }, - filter: ['hello searchSource filter 1'], - }, - }, - columns: ['larry'], - uiState: null, - }, - searchSourceFilter: { isSearchSourceFilter: true, isFilter: true }, - queryFilter: { isQueryFilter: true, isFilter: true }, - }; - }); - - describe('search', () => { - it('for timebased search', () => { - const filters = getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr, - args.searchSourceFilter, - args.queryFilter - ); - - expect(filters).toEqual({ - combinedFilter: [ - { - range: { - testtimestamp: { - format: 'strict_date_time', - gte: '1901-01-01T00:00:00Z', - lte: '1902-01-01T00:00:00Z', - }, - }, - }, - { isFilter: true, isSearchSourceFilter: true }, - { isFilter: true, isQueryFilter: true }, - ], - includes: ['testtimestamp', 'larry'], - timezone: 'UTC', - }); - }); - - it('for non-timebased search', () => { - args.indexPatternTimeField = null; - args.timerange = null; - - const filters = getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr, - args.searchSourceFilter, - args.queryFilter - ); - - expect(filters).toEqual({ - combinedFilter: [ - { isFilter: true, isSearchSourceFilter: true }, - { isFilter: true, isQueryFilter: true }, - ], - includes: ['larry'], - timezone: null, - }); - }); - }); - - describe('errors', () => { - it('throw if timebased and timerange is missing', () => { - args.timerange = null; - - const throwFn = () => - getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr, - args.searchSourceFilter, - args.queryFilter - ); - - expect(throwFn).toThrow( - 'Time range params are required for index pattern [logs-test-*], using time field [testtimestamp]' - ); - }); - }); - - it('composes the defined filters', () => { - expect( - getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr, - undefined, - undefined - ) - ).toEqual({ - combinedFilter: [ - { - range: { - testtimestamp: { - format: 'strict_date_time', - gte: '1901-01-01T00:00:00Z', - lte: '1902-01-01T00:00:00Z', - }, - }, - }, - ], - includes: ['testtimestamp', 'larry'], - timezone: 'UTC', - }); - - expect( - getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr, - undefined, - args.queryFilter - ) - ).toEqual({ - combinedFilter: [ - { - range: { - testtimestamp: { - format: 'strict_date_time', - gte: '1901-01-01T00:00:00Z', - lte: '1902-01-01T00:00:00Z', - }, - }, - }, - { isFilter: true, isQueryFilter: true }, - ], - includes: ['testtimestamp', 'larry'], - timezone: 'UTC', - }); - }); - - describe('timefilter', () => { - it('formats the datetime to the provided timezone', () => { - args.timerange = { - timezone: 'MST', - min: '1901-01-01T00:00:00Z', - max: '1902-01-01T00:00:00Z', - }; - - expect( - getFilters( - args.indexPatternId, - args.indexPatternTimeField, - args.timerange, - args.savedSearchObjectAttr - ) - ).toEqual({ - combinedFilter: [ - { - range: { - testtimestamp: { - format: 'strict_date_time', - gte: '1900-12-31T17:00:00-07:00', - lte: '1901-12-31T17:00:00-07:00', - }, - }, - }, - ], - includes: ['testtimestamp', 'larry'], - timezone: 'MST', - }); - }); - }); -}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.ts deleted file mode 100644 index c252b66952360..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/lib/get_filters.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { badRequest } from '@hapi/boom'; -import moment from 'moment-timezone'; -import { TimeRangeParams } from '../../common'; -import { Filter, QueryFilter, SavedSearchObjectAttributes, SearchSourceFilter } from '../types'; - -export function getFilters( - indexPatternId: string, - indexPatternTimeField: string | null, - timerange: TimeRangeParams | null, - savedSearchObjectAttr: SavedSearchObjectAttributes, - searchSourceFilter?: SearchSourceFilter, - queryFilter?: QueryFilter -) { - let includes: string[]; - let timeFilter: any | null; - let timezone: string | null; - - if (indexPatternTimeField) { - if (!timerange || timerange.min == null || timerange.max == null) { - throw badRequest( - `Time range params are required for index pattern [${indexPatternId}], using time field [${indexPatternTimeField}]` - ); - } - - timezone = timerange.timezone; - const { min: gte, max: lte } = timerange; - timeFilter = { - range: { - [indexPatternTimeField]: { - format: 'strict_date_time', - gte: moment.tz(moment(gte), timezone).format(), - lte: moment.tz(moment(lte), timezone).format(), - }, - }, - }; - - const savedSearchCols = savedSearchObjectAttr.columns || []; - includes = [indexPatternTimeField, ...savedSearchCols]; - } else { - includes = savedSearchObjectAttr.columns || []; - timeFilter = null; - timezone = null; - } - - const combinedFilter: Filter[] = [timeFilter, searchSourceFilter, queryFilter].filter(Boolean); // builds an array of defined filters - - return { timezone, combinedFilter, includes }; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts deleted file mode 100644 index a4fbdb69bbbba..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { TimeRangeParams } from '../common'; - -export interface FakeRequest { - headers: Record; -} - -export interface JobParamsPanelCsvPost { - timerange?: TimeRangeParams; - state?: any; -} - -export interface SearchPanel { - indexPatternSavedObjectId: string; - attributes: SavedSearchObjectAttributes; - timerange?: TimeRangeParams; -} - -export interface JobPayloadPanelCsv extends JobParamsPanelCsv { - panel: SearchPanel; -} - -export interface JobParamsPanelCsv { - savedObjectType: string; - savedObjectId: string; - post?: JobParamsPanelCsvPost; - visType?: string; -} - -export interface SavedObjectServiceError { - statusCode: number; - error?: string; - message?: string; -} - -export interface SavedObjectMetaJSON { - searchSourceJSON: string; -} - -export interface SavedObjectMeta { - searchSource: SearchSource; -} - -export interface SavedSearchObjectAttributesJSON { - title: string; - sort: any[]; - columns: string[]; - kibanaSavedObjectMeta: SavedObjectMetaJSON; - uiState: any; -} - -export interface SavedSearchObjectAttributes { - title: string; - sort: any[]; - columns?: string[]; - kibanaSavedObjectMeta: SavedObjectMeta; - uiState: any; -} - -export interface VisObjectAttributesJSON { - title: string; - visState: string; // JSON string - type: string; - params: any; - uiStateJSON: string; // also JSON string - aggs: any[]; - sort: any[]; - kibanaSavedObjectMeta: SavedObjectMeta; -} - -export interface VisObjectAttributes { - title: string; - visState: string; // JSON string - type: string; - params: any; - uiState: { - vis: { - params: { - sort: { - columnIndex: string; - direction: string; - }; - }; - }; - }; - aggs: any[]; - sort: any[]; - kibanaSavedObjectMeta: SavedObjectMeta; -} - -export interface SavedObjectReference { - name: string; // should be kibanaSavedObjectMeta.searchSourceJSON.index - type: string; // should be index-pattern - id: string; -} - -export interface SavedObject { - attributes: any; - references: SavedObjectReference[]; -} - -export interface VisPanel { - indexPatternSavedObjectId?: string; - savedSearchObjectId?: string; - attributes: VisObjectAttributes; - timerange: TimeRangeParams; -} - -export interface DocValueFields { - field: string; - format: string; -} - -export interface SearchSourceQuery { - isSearchSourceQuery: boolean; -} - -export interface SearchSource { - query: SearchSourceQuery; - filter: any[]; -} - -/* - * These filter types are stub types to help ensure things get passed to - * non-Typescript functions in the right order. An actual structure is not - * needed because the code doesn't look into the properties; just combines them - * and passes them through to other non-TS modules. - */ -export interface Filter { - isFilter: boolean; -} -export interface TimeFilter extends Filter { - isTimeFilter: boolean; -} -export interface QueryFilter extends Filter { - isQueryFilter: boolean; -} -export interface SearchSourceFilter extends Filter { - isSearchSourceFilter: boolean; -} - -export interface IndexPatternField { - scripted: boolean; - lang?: string; - script?: string; - name: string; -} diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/create_job.ts new file mode 100644 index 0000000000000..a389f2a3252ca --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/create_job.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CSV_JOB_TYPE } from '../../../common/constants'; +import { cryptoFactory } from '../../lib'; +import { CreateJobFn, CreateJobFnFactory } from '../../types'; +import { JobParamsCSV, TaskPayloadCSV } from './types'; + +export const createJobFnFactory: CreateJobFnFactory< + CreateJobFn +> = function createJobFactoryFn(reporting, parentLogger) { + const logger = parentLogger.clone([CSV_JOB_TYPE, 'create-job']); + + const config = reporting.getConfig(); + const crypto = cryptoFactory(config.get('encryptionKey')); + + return async function createJob(jobParams, context, request) { + const serializedEncryptedHeaders = await crypto.encrypt(request.headers); + + return { + headers: serializedEncryptedHeaders, + spaceId: reporting.getSpaceId(request, logger), + ...jobParams, + }; + }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.test.ts new file mode 100644 index 0000000000000..1c2e15ebc5d9b --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +jest.mock('./generate_csv/generate_csv', () => ({ + CsvGenerator: class CsvGeneratorMock { + generateData() { + return { + content: 'test\n123', + }; + } + }, +})); + +import nodeCrypto from '@elastic/node-crypto'; +import { ReportingCore } from '../../'; +import { CancellationToken } from '../../../common'; +import { + createMockConfig, + createMockConfigSchema, + createMockLevelLogger, + createMockReportingCore, +} from '../../test_helpers'; +import { runTaskFnFactory } from './execute_job'; + +const logger = createMockLevelLogger(); +const encryptionKey = 'tetkey'; +const headers = { sid: 'cooltestheaders' }; +let encryptedHeaders: string; +let reportingCore: ReportingCore; + +beforeAll(async () => { + const crypto = nodeCrypto({ encryptionKey }); + const config = createMockConfig( + createMockConfigSchema({ + encryptionKey, + csv: { + checkForFormulas: true, + escapeFormulaValues: true, + maxSizeBytes: 180000, + scroll: { size: 500, duration: '30s' }, + }, + }) + ); + + encryptedHeaders = await crypto.encrypt(headers); + + reportingCore = await createMockReportingCore(config); +}); + +test('gets the csv content from job parameters', async () => { + const runTask = runTaskFnFactory(reportingCore, logger); + + const payload = await runTask( + 'cool-job-id', + { + headers: encryptedHeaders, + browserTimezone: 'US/Alaska', + searchSource: {}, + objectType: 'search', + title: 'Test Search', + }, + new CancellationToken() + ); + + expect(payload).toMatchInlineSnapshot(` + Object { + "content": "test + 123", + } + `); +}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts new file mode 100644 index 0000000000000..0453af4ef23e3 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CSV_JOB_TYPE } from '../../../common/constants'; +import { RunTaskFn, RunTaskFnFactory } from '../../types'; +import { decryptJobHeaders } from '../common'; +import { CsvGenerator } from './generate_csv/generate_csv'; +import { TaskPayloadCSV } from './types'; +import { getFieldFormats } from '../../services'; + +export const runTaskFnFactory: RunTaskFnFactory> = ( + reporting, + parentLogger +) => { + const config = reporting.getConfig(); + + return async function runTask(jobId, job, cancellationToken) { + const logger = parentLogger.clone([CSV_JOB_TYPE, 'execute-job', jobId]); + + const encryptionKey = config.get('encryptionKey'); + const headers = await decryptJobHeaders(encryptionKey, job.headers, logger); + const fakeRequest = reporting.getFakeRequest({ headers }, job.spaceId, logger); + const uiSettingsClient = await reporting.getUiSettingsClient(fakeRequest, logger); + + const searchService = await reporting.getSearchService(); + const searchSourceService = await searchService.searchSource.asScoped(fakeRequest); + const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( + uiSettingsClient + ); + + const esClient = (await reporting.getEsClient()).asScoped(fakeRequest); + + const csv = new CsvGenerator( + job, + config, + esClient, + uiSettingsClient, + searchSourceService, + fieldFormatsRegistry, + cancellationToken, + logger + ); + + return await csv.generateData(); + }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/cell_has_formula.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/cell_has_formula.ts similarity index 100% rename from x-pack/plugins/reporting/server/export_types/csv/generate_csv/cell_has_formula.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/cell_has_formula.ts diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/escape_value.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.test.ts similarity index 100% rename from x-pack/plugins/reporting/server/export_types/csv/generate_csv/escape_value.test.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.test.ts diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/escape_value.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.ts similarity index 100% rename from x-pack/plugins/reporting/server/export_types/csv/generate_csv/escape_value.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.ts diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts new file mode 100644 index 0000000000000..430f8cadbe90d --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts @@ -0,0 +1,551 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { identity, range } from 'lodash'; +import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, + uiSettingsServiceMock, +} from 'src/core/server/mocks'; +import { + EsQuerySearchAfter, + FieldFormatsRegistry, + ISearchStartSearchSource, +} from 'src/plugins/data/common'; +import { searchSourceInstanceMock } from 'src/plugins/data/common/search/search_source/mocks'; +import { ReportingConfig } from '../../../'; +import { CancellationToken } from '../../../../common'; +import { + UI_SETTINGS_CSV_QUOTE_VALUES, + UI_SETTINGS_CSV_SEPARATOR, + UI_SETTINGS_DATEFORMAT_TZ, +} from '../../../../common/constants'; +import { + createMockConfig, + createMockConfigSchema, + createMockLevelLogger, +} from '../../../test_helpers'; +import { JobParamsCSV } from '../types'; +import { CsvGenerator } from './generate_csv'; + +const createMockJob = (baseObj: any = {}): JobParamsCSV => ({ + ...baseObj, +}); + +let mockEsClient: IScopedClusterClient; +let mockConfig: ReportingConfig; +let uiSettingsClient: IUiSettingsClient; + +const searchSourceMock = { ...searchSourceInstanceMock }; +const mockSearchSourceService: jest.Mocked = { + create: jest.fn().mockReturnValue(searchSourceMock), + createEmpty: jest.fn().mockReturnValue(searchSourceMock), +}; +const mockSearchSourceFetchDefault = jest.fn().mockResolvedValue({ + hits: { + hits: [], + total: 0, + }, +}); +const mockSearchSourceGetFieldDefault = jest.fn().mockImplementation((key: string) => { + switch (key) { + case 'fields': + return ['date', 'ip', 'message']; + case 'index': + return { + fields: { + getByName: jest.fn().mockImplementation(() => []), + getByType: jest.fn().mockImplementation(() => []), + }, + getFormatterForField: jest.fn(), + }; + } +}); + +const mockFieldFormatsRegistry = ({ + deserialize: jest + .fn() + .mockImplementation(() => ({ id: 'string', convert: jest.fn().mockImplementation(identity) })), +} as unknown) as FieldFormatsRegistry; + +beforeEach(async () => { + mockEsClient = elasticsearchServiceMock.createScopedClusterClient(); + + uiSettingsClient = uiSettingsServiceMock + .createStartContract() + .asScopedToClient(savedObjectsClientMock.create()); + uiSettingsClient.get = jest.fn().mockImplementation((key): any => { + switch (key) { + case UI_SETTINGS_CSV_QUOTE_VALUES: + return true; + case UI_SETTINGS_CSV_SEPARATOR: + return ','; + case UI_SETTINGS_DATEFORMAT_TZ: + return 'Browser'; + } + }); + + mockConfig = createMockConfig( + createMockConfigSchema({ + csv: { + checkForFormulas: true, + escapeFormulaValues: true, + maxSizeBytes: 180000, + scroll: { size: 500, duration: '30s' }, + }, + }) + ); + + searchSourceMock.getField = mockSearchSourceGetFieldDefault; + searchSourceMock.fetch = mockSearchSourceFetchDefault; +}); + +const logger = createMockLevelLogger(); + +it('formats an empty search result to CSV content', async () => { + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,message + " + `); + expect(csvResult.csv_contains_formulas).toBe(false); + expect(csvResult.needs_sorting).toBe(false); +}); + +it('formats a search result to CSV content', async () => { + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + fields: { + date: `["2020-12-31T00:14:28.000Z"]`, + ip: `["110.135.176.89"]`, + message: `["This is a great message!"]`, + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,message + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is a great message!\\" + " + `); + expect(csvResult.csv_contains_formulas).toBe(false); + expect(csvResult.needs_sorting).toBe(false); +}); + +const TEST_NUM_TOTAL = 100; + +it('calculates the bytes of the content', async () => { + searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { + if (key === 'fields') { + return ['message']; + } + return mockSearchSourceGetFieldDefault(key); + }); + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: range(0, TEST_NUM_TOTAL).map((hit, i) => ({ + fields: { + message: ['this is a great message'], + }, + sort: [i, 1] as EsQuerySearchAfter, + })), + total: TEST_NUM_TOTAL, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.size).toBe(2608); + expect(csvResult.max_size_reached).toBe(false); + expect(csvResult.needs_sorting).toBe(false); + expect(csvResult.warnings).toEqual([]); +}); + +it('warns if max size was reached', async () => { + const TEST_MAX_SIZE = 500; + + mockConfig = createMockConfig( + createMockConfigSchema({ + csv: { + checkForFormulas: true, + escapeFormulaValues: true, + maxSizeBytes: TEST_MAX_SIZE, + scroll: { size: 500, duration: '30s' }, + }, + }) + ); + + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: range(0, TEST_NUM_TOTAL).map((hit, i) => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['super cali fragile istic XPLA docious'], + }, + sort: [i, ''] as EsQuerySearchAfter, + })), + total: TEST_NUM_TOTAL, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.max_size_reached).toBe(true); + expect(csvResult.needs_sorting).toBe(false); + expect(csvResult.warnings).toEqual([]); + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,message + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" + " + `); +}); + +it('warns if it detects paging through unsorted search results', async () => { + searchSourceMock.fetch = jest.fn().mockResolvedValue({ + hits: { + hits: range(0, 15).map(() => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['super cali fragile istic XPLA docious'], + }, + })), + total: 50, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.needs_sorting).toBe(true); +}); + +it('warns if it detects paging through poorly sorted data', async () => { + searchSourceMock.fetch = jest.fn().mockResolvedValue({ + hits: { + hits: range(0, 15).map(() => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['super cali fragile istic XPLA docious'], + sort: [0, 0] as EsQuerySearchAfter, + }, + })), + total: 50, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + expect(csvResult.needs_sorting).toBe(true); +}); + +describe('fields', () => { + it('cells can be multi-value', async () => { + searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { + if (key === 'fields') { + return ['_id', 'sku']; + } + return mockSearchSourceGetFieldDefault(key); + }); + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + _id: 'my-cool-id', + _index: 'my-cool-index', + _version: 4, + fields: { + sku: [`This is a cool SKU.`, `This is also a cool SKU.`], + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({ searchSource: {} }), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchInlineSnapshot(` + "\\"_id\\",sku + \\"my-cool-id\\",\\"This is a cool SKU., This is also a cool SKU.\\" + " + `); + expect(csvResult.needs_sorting).toBe(false); + }); + + it('provides top-level underscored fields as columns', async () => { + searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { + if (key === 'fields') { + return ['_id', '_index', 'date', 'message']; + } + return mockSearchSourceGetFieldDefault(key); + }); + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + _id: 'my-cool-id', + _index: 'my-cool-index', + _version: 4, + fields: { + date: ['2020-12-31T00:14:28.000Z'], + message: [`it's nice to see you`], + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({ + searchSource: { + query: { query: '', language: 'kuery' }, + sort: [{ '@date': 'desc' }], + index: '93f4bc50-6662-11eb-98bc-f550e2308366', + fields: ['_id', '_index', '@date', 'message'], + filter: [], + }, + }), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchInlineSnapshot(` + "\\"_id\\",\\"_index\\",date,message + \\"my-cool-id\\",\\"my-cool-index\\",\\"2020-12-31T00:14:28.000Z\\",\\"it's nice to see you\\" + " + `); + expect(csvResult.csv_contains_formulas).toBe(false); + expect(csvResult.needs_sorting).toBe(false); + }); +}); + +describe('formulas', () => { + const TEST_FORMULA = '=SUM(A1:A2)'; + + it(`escapes formula values in a cell, doesn't warn the csv contains formulas`, async () => { + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: [TEST_FORMULA], + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,message + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"'=SUM(A1:A2)\\" + " + `); + expect(csvResult.csv_contains_formulas).toBe(false); + expect(csvResult.needs_sorting).toBe(false); + }); + + it(`escapes formula values in a header, doesn't warn the csv contains formulas`, async () => { + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + [TEST_FORMULA]: 'This is great data', + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + + searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { + if (key === 'fields') { + return ['date', 'ip', TEST_FORMULA]; + } + return mockSearchSourceGetFieldDefault(key); + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,\\"'=SUM(A1:A2)\\" + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is great data\\" + " + `); + expect(csvResult.csv_contains_formulas).toBe(false); + expect(csvResult.needs_sorting).toBe(false); + }); + + it('can check for formulas, without escaping them', async () => { + mockConfig = createMockConfig( + createMockConfigSchema({ + csv: { + checkForFormulas: true, + escapeFormulaValues: false, + maxSizeBytes: 180000, + scroll: { size: 500, duration: '30s' }, + }, + }) + ); + searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: [TEST_FORMULA], + }, + sort: [1, 'a'] as EsQuerySearchAfter, + }, + ], + total: 1, + }, + }); + + const generateCsv = new CsvGenerator( + createMockJob({}), + mockConfig, + mockEsClient, + uiSettingsClient, + mockSearchSourceService, + mockFieldFormatsRegistry, + new CancellationToken(), + logger + ); + + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchInlineSnapshot(` + "date,ip,message + \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"=SUM(A1:A2)\\" + " + `); + expect(csvResult.csv_contains_formulas).toBe(true); + expect(csvResult.needs_sorting).toBe(false); + }); +}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts new file mode 100644 index 0000000000000..9c0486a40fee9 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -0,0 +1,394 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { SearchResponse } from 'elasticsearch'; +import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; +import { Datatable } from 'src/plugins/expressions/server'; +import { ReportingConfig } from '../../..'; +import { + EsQuerySearchAfter, + FieldFormat, + FieldFormatConfig, + IFieldFormatsRegistry, + ISearchStartSearchSource, + SearchFieldValue, + tabifyDocs, +} from '../../../../../../../src/plugins/data/common'; +import { CancellationToken } from '../../../../common'; +import { CONTENT_TYPE_CSV } from '../../../../common/constants'; +import { byteSizeValueToNumber } from '../../../../common/schema_utils'; +import { LevelLogger } from '../../../lib'; +import { TaskRunResult } from '../../../lib/tasks'; +import { JobParamsCSV } from '../types'; +import { cellHasFormulas } from './cell_has_formula'; +import { CsvExportSettings, getExportSettings } from './get_export_settings'; +import { MaxSizeStringBuilder } from './max_size_string_builder'; + +export class CsvGenerator { + private _columnMap: number[] | null = null; + private _formatters: Record | null = null; + private csvContainsFormulas = false; + private maxSizeReached = false; + private needsSorting = false; + private csvRowCount = 0; + + constructor( + private job: JobParamsCSV, + private config: ReportingConfig, + private esClient: IScopedClusterClient, + private uiSettingsClient: IUiSettingsClient, + private searchSourceService: ISearchStartSearchSource, + private fieldFormatsRegistry: IFieldFormatsRegistry, + private cancellationToken: CancellationToken, + private logger: LevelLogger + ) {} + + /* + * Build a map for ordering the fields of search results into CSV columns + */ + private getColumnMap(fields: SearchFieldValue[] | undefined, table: Datatable) { + if (this._columnMap) { + return this._columnMap; + } + + // if there are selected fields, re-initialize columnMap with field order is set in searchSource fields + if (fields && fields[0] !== '*') { + this._columnMap = fields.map((field) => + table.columns.findIndex((column) => column.id === field) + ); + } + + // initialize default columnMap, works if fields are asterisk and order doesn't matter + if (!this._columnMap) { + this._columnMap = table.columns.map((c, columnIndex) => columnIndex); + } + + return this._columnMap; + } + + /* + * Load field formats for each field in the list + */ + private getFormatters(table: Datatable) { + if (this._formatters) { + return this._formatters; + } + + // initialize field formats + const formatters: Record = {}; + table.columns.forEach((c) => { + const fieldFormat = this.fieldFormatsRegistry.deserialize(c.meta.params); + formatters[c.id] = fieldFormat; + }); + + this._formatters = formatters; + return this._formatters; + } + + /* + * Use the list of fields to generate the header row + */ + private generateHeader( + fields: SearchFieldValue[] | undefined, + table: Datatable, + builder: MaxSizeStringBuilder, + settings: CsvExportSettings + ) { + const { checkForFormulas, escapeValue, separator } = settings; + const columnMap = this.getColumnMap(fields, table); + + this.logger.debug(`Building CSV header row...`); + const header = + columnMap + .map((columnIndex, position) => { + let value: string; + if (columnIndex > -1) { + value = table.columns[columnIndex].name; + } else { + value = fields && fields[position] ? (fields[position] as string) : 'unknown'; + } + + if (checkForFormulas && cellHasFormulas(value)) { + this.csvContainsFormulas = true; // set warning if heading value has a formula + } + + return escapeValue(value); + }) + .join(separator) + `\n`; + + if (!builder.tryAppend(header)) { + return { + size: 0, + content: '', + maxSizeReached: true, + warnings: [], + }; + } + } + + /* + * Format a Datatable into rows of CSV content + */ + private generateRows( + fields: SearchFieldValue[] | undefined, + table: Datatable, + builder: MaxSizeStringBuilder, + formatters: Record, + settings: CsvExportSettings + ) { + // write the rows + this.logger.debug(`Building ${table.rows.length} CSV data rows...`); + const { checkForFormulas, escapeValue, separator } = settings; + + for (const dataTableRow of table.rows) { + if (this.cancellationToken.isCancelled()) { + break; + } + + const columnMap = this.getColumnMap(fields, table); + const row = + columnMap + .map((columnIndex, position) => { + const tableColumn = table.columns[columnIndex]; + let cell: string[] | string = '-'; + + if (tableColumn != null) { + cell = formatters[tableColumn.id].convert(dataTableRow[tableColumn.id]); + + try { + // expected values are a string of JSON where the value(s) is in an array + cell = JSON.parse(cell); + } catch (e) { + // ignore + } + + // We have to strip singular array values out of their array wrapper, + // So that the value appears the visually the same as seen in Discover + if (Array.isArray(cell)) { + cell = cell.join(', '); // mimic Discover behavior + } + } else { + this.logger.warn(`Unrecognized field: ${(fields && fields[position]) || 'unknown'}`); + } + + return cell; + }) + .map((value) => { + if (checkForFormulas && cellHasFormulas(value)) { + this.csvContainsFormulas = true; // set warning if cell value has a formula + } + // Escape the values in Data + return escapeValue(value); + }) + .join(separator) + '\n'; + + if (!builder.tryAppend(row)) { + this.logger.warn('max Size Reached'); + this.maxSizeReached = true; + if (this.cancellationToken) { + this.cancellationToken.cancel(); + } + break; + } + + this.csvRowCount++; + } + } + + /* + * Open a Point In Time on the Elasticsearch index and collect all the data from the index + */ + public async generateData(): Promise { + const [settings, searchSource] = await Promise.all([ + getExportSettings(this.uiSettingsClient, this.config, this.job.browserTimezone, this.logger), + this.searchSourceService.create(this.job.searchSource), + ]); + + const index = searchSource.getField('index'); + const fields = searchSource.getField('fields'); + + const { maxSizeBytes, bom, escapeFormulaValues } = settings; + searchSource.setField('size', settings.scroll.size); + + const builder = new MaxSizeStringBuilder(byteSizeValueToNumber(maxSizeBytes), bom); + + let currentRecord = -1; + let totalRecords = 0; + let first = true; + let lastSortId: EsQuerySearchAfter | undefined; + let pitId: string | undefined; + const warnings: string[] = []; + + // open PIT and set field format config + if (index) { + // use _pit API + const { title: indexPatternTitle } = index; + const { duration } = settings.scroll; + this.logger.debug(`Open PIT: index: '${indexPatternTitle}' keep_alive: '${duration}'`); + const { body, statusCode } = await this.esClient.asCurrentUser.openPointInTime({ + index: indexPatternTitle, + keep_alive: duration, + }); + if (statusCode === 404) { + this.logger.error('Unable to open point in time!'); + this.logger.error(new Error(JSON.stringify(body))); + } + pitId = body.id as string; + + // apply timezone from the job to all date field formatters + try { + index.fields.getByType('date').forEach(({ name }) => { + this.logger.debug(`setting timezone on ${name}`); + const format: FieldFormatConfig = { + ...index.fieldFormatMap[name], + id: index.fieldFormatMap[name]?.id || 'date', // allow id: date_nanos + params: { + ...index.fieldFormatMap[name]?.params, + timezone: settings.timezone, + }, + }; + index.setFieldFormat(name, format); + }); + } catch (err) { + this.logger.error(err); + } + } + + this.logger.debug(`Received PIT ID: ${pitId?.substring(0, 9)}`); + if (pitId) { + searchSource.setField('pit', { id: pitId, keep_alive: '2m' }); + } else { + this.logger.error(`Unable to open a point in time with ${searchSource.getId()}!`); + } + + do { + if (this.cancellationToken.isCancelled()) { + break; + } + + if (lastSortId) { + searchSource.setField('searchAfter', lastSortId); + } + let results: SearchResponse | undefined; + try { + results = await searchSource.fetch(); + } catch (err) { + this.logger.error(err); + } + + if (!results) { + break; + } + + if (results.hits?.total == null) { + this.logger.error('Expected total number of records in the search response'); + totalRecords = -1; + } else { + totalRecords = results.hits.total; + } + this.logger.debug(`Search results: ${totalRecords}`); + + let table: Datatable | undefined; + try { + table = tabifyDocs(results, index, { shallow: true, meta: true }); + } catch (err) { + this.logger.error(err); + } + + if (!table) { + break; + } + + // write the header and initialize formatters / column orderings + // depends on the table to know what order to place the columns + if (first) { + first = false; + this.generateHeader(fields, table, builder, settings); + } + + if (table.rows.length < 1) { + break; // empty report with just the header + } + + const formatters = this.getFormatters(table); + this.generateRows(fields, table, builder, formatters, settings); + + const hits = results.hits?.hits || []; + + let tempSortId: EsQuerySearchAfter | undefined; + try { + tempSortId = hits[hits.length - 1]?.sort as EsQuerySearchAfter; + if (lastSortId && tempSortId?.join() === lastSortId?.join()) { + // repeated sort ID: results are not thoroughly sorted + this.needsSorting = true; + } + + const uniqueSortIds = new Set(); + hits.forEach((hit) => { + uniqueSortIds.add(hit.sort?.join()); + }); + if (lastSortId && (!uniqueSortIds.size || uniqueSortIds.size < hits.length)) { + // not enough unique sort IDs for the number of hits: results are not thoroughly sorted + this.needsSorting = true; + } + } catch (err) { + this.logger.error(err); + } + + // update last sort ID for next query + lastSortId = tempSortId; + + // update iterator + currentRecord += table.rows.length; + } while (currentRecord < totalRecords - 1); + + const size = builder.getSizeInBytes(); + this.logger.debug( + `Finished generating. Total size in bytes: ${size}. Row count: ${this.csvRowCount}.` + ); + + // the row count is wrong and it's not because of max size limit + // results are not thoroughly sorted + if (this.csvRowCount !== totalRecords && !this.maxSizeReached) { + this.needsSorting = true; + } + + // Add warnings to be logged + if (this.csvContainsFormulas && escapeFormulaValues) { + warnings.push( + i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues', { + defaultMessage: 'CSV may contain formulas whose values have been escaped', + }) + ); + } + + if (this.needsSorting) { + warnings.push( + i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.unsortedResults', { + defaultMessage: `The export may have duplicated or missing data: sort values in the search results must be unique`, + }) + ); + } + + // clean PIT + if (pitId) { + this.logger.debug(`Closing PIT`); + await this.esClient.asCurrentUser.closePointInTime({ body: { id: pitId } }); + } + + return { + content: builder.getString(), + content_type: CONTENT_TYPE_CSV, + csv_contains_formulas: this.csvContainsFormulas && !escapeFormulaValues, + max_size_reached: this.maxSizeReached, + needs_sorting: this.needsSorting, + size, + warnings, + }; + } +} diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.test.ts new file mode 100644 index 0000000000000..efdb583a89dc8 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + UI_SETTINGS_DATEFORMAT_TZ, + UI_SETTINGS_CSV_QUOTE_VALUES, + UI_SETTINGS_CSV_SEPARATOR, +} from '../../../../common/constants'; +import { IUiSettingsClient } from 'kibana/server'; +import { savedObjectsClientMock, uiSettingsServiceMock } from 'src/core/server/mocks'; +import { + createMockConfig, + createMockConfigSchema, + createMockLevelLogger, +} from '../../../test_helpers'; +import { getExportSettings } from './get_export_settings'; + +describe('getExportSettings', () => { + let uiSettingsClient: IUiSettingsClient; + const config = createMockConfig(createMockConfigSchema({})); + const logger = createMockLevelLogger(); + + beforeEach(() => { + uiSettingsClient = uiSettingsServiceMock + .createStartContract() + .asScopedToClient(savedObjectsClientMock.create()); + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + switch (key) { + case UI_SETTINGS_CSV_QUOTE_VALUES: + return true; + case UI_SETTINGS_CSV_SEPARATOR: + return ','; + case UI_SETTINGS_DATEFORMAT_TZ: + return 'Browser'; + } + + return 'helo world'; + }); + }); + + test('getExportSettings: returns the expected result', async () => { + expect(await getExportSettings(uiSettingsClient, config, '', logger)).toMatchInlineSnapshot(` + Object { + "bom": "", + "checkForFormulas": undefined, + "escapeFormulaValues": undefined, + "escapeValue": [Function], + "maxSizeBytes": undefined, + "scroll": Object { + "duration": undefined, + "size": undefined, + }, + "separator": ",", + "timezone": "UTC", + } + `); + }); + + test('escapeValue function', async () => { + const { escapeValue } = await getExportSettings(uiSettingsClient, config, '', logger); + expect(escapeValue(`test`)).toBe(`test`); + expect(escapeValue(`this is, a test`)).toBe(`"this is, a test"`); + expect(escapeValue(`"tet"`)).toBe(`"""tet"""`); + expect(escapeValue(`@foo`)).toBe(`"@foo"`); + }); + + test('non-default timezone', async () => { + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + switch (key) { + case UI_SETTINGS_DATEFORMAT_TZ: + return `America/Aruba`; + } + }); + + expect( + await getExportSettings(uiSettingsClient, config, '', logger).then(({ timezone }) => timezone) + ).toBe(`America/Aruba`); + }); +}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts new file mode 100644 index 0000000000000..17a10f3034242 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; +import { IUiSettingsClient } from 'kibana/server'; +import { ReportingConfig } from '../../../'; +import { + CSV_BOM_CHARS, + UI_SETTINGS_DATEFORMAT_TZ, + UI_SETTINGS_CSV_QUOTE_VALUES, + UI_SETTINGS_CSV_SEPARATOR, +} from '../../../../common/constants'; +import { LevelLogger } from '../../../lib'; +import { createEscapeValue } from './escape_value'; + +export interface CsvExportSettings { + timezone: string; + scroll: { + size: number; + duration: string; + }; + bom: string; + separator: string; + maxSizeBytes: number | ByteSizeValue; + checkForFormulas: boolean; + escapeFormulaValues: boolean; + escapeValue: (value: string) => string; +} + +export const getExportSettings = async ( + client: IUiSettingsClient, + config: ReportingConfig, + timezone: string | undefined, + logger: LevelLogger +): Promise => { + // Timezone + let setTimezone: string; + // timezone in job params? + if (timezone) { + setTimezone = timezone; + } else { + // timezone in settings? + setTimezone = await client.get(UI_SETTINGS_DATEFORMAT_TZ); + if (setTimezone === 'Browser') { + // if `Browser`, hardcode it to 'UTC' so the export has data that makes sense + logger.warn( + i18n.translate('xpack.reporting.exportTypes.csv.executeJob.dateFormateSetting', { + defaultMessage: + 'Kibana Advanced Setting "{dateFormatTimezone}" is set to "Browser". Dates will be formatted as UTC to avoid ambiguity.', + values: { dateFormatTimezone: 'dateFormat:tz' }, + }) + ); + setTimezone = 'UTC'; + } + } + + // Separator, QuoteValues + const [separator, quoteValues] = await Promise.all([ + client.get(UI_SETTINGS_CSV_SEPARATOR), + client.get(UI_SETTINGS_CSV_QUOTE_VALUES), + ]); + + const escapeFormulaValues = config.get('csv', 'escapeFormulaValues'); + const escapeValue = createEscapeValue(quoteValues, escapeFormulaValues); + const bom = config.get('csv', 'useByteOrderMarkEncoding') ? CSV_BOM_CHARS : ''; + + return { + timezone: setTimezone, + scroll: { + size: config.get('csv', 'scroll', 'size'), + duration: config.get('csv', 'scroll', 'duration'), + }, + bom, + separator, + maxSizeBytes: config.get('csv', 'maxSizeBytes'), + checkForFormulas: config.get('csv', 'checkForFormulas'), + escapeFormulaValues, + escapeValue, + }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/index.ts new file mode 100644 index 0000000000000..4e08ff2a222dc --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { CsvGenerator } from './generate_csv'; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/max_size_string_builder.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/max_size_string_builder.test.ts similarity index 100% rename from x-pack/plugins/reporting/server/export_types/csv/generate_csv/max_size_string_builder.test.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/max_size_string_builder.test.ts diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/max_size_string_builder.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/max_size_string_builder.ts similarity index 100% rename from x-pack/plugins/reporting/server/export_types/csv/generate_csv/max_size_string_builder.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/max_size_string_builder.ts diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/index.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/index.ts new file mode 100644 index 0000000000000..65126a0a62cb8 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + CSV_JOB_TYPE as jobType, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_ENTERPRISE, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_TRIAL, +} from '../../../common/constants'; +import { CreateJobFn, ExportTypeDefinition, RunTaskFn } from '../../types'; +import { createJobFnFactory } from './create_job'; +import { runTaskFnFactory } from './execute_job'; +import { metadata } from './metadata'; +import { JobParamsCSV, TaskPayloadCSV } from './types'; + +export const getExportType = (): ExportTypeDefinition< + CreateJobFn, + RunTaskFn +> => ({ + ...metadata, + jobType, + jobContentExtension: 'csv', + createJobFnFactory, + runTaskFnFactory, + validLicenses: [ + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, + ], +}); diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/metadata.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/metadata.ts similarity index 65% rename from x-pack/plugins/reporting/server/export_types/csv_from_savedobject/metadata.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource/metadata.ts index 76bf106acb5de..187d64d872a9d 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/metadata.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/metadata.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; +import { CSV_JOB_TYPE } from '../../../common/constants'; export const metadata = { - id: CSV_FROM_SAVEDOBJECT_JOB_TYPE, - name: CSV_FROM_SAVEDOBJECT_JOB_TYPE, + id: 'csv_searchsource', + name: CSV_JOB_TYPE, }; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.d.ts new file mode 100644 index 0000000000000..f0ad4e00ebd5c --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/types.d.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BaseParams, BasePayload } from '../../types'; + +export type RawValue = string | object | null | undefined; + +interface BaseParamsCSV { + browserTimezone: string; + searchSource: any; +} + +export type JobParamsCSV = BaseParamsCSV & BaseParams; +export type TaskPayloadCSV = BaseParamsCSV & BasePayload; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts new file mode 100644 index 0000000000000..eab8a06b10121 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaRequest } from 'src/core/server'; +import { CancellationToken } from '../../../common'; +import { CSV_SEARCHSOURCE_IMMEDIATE_TYPE } from '../../../common/constants'; +import { TaskRunResult } from '../../lib/tasks'; +import { getFieldFormats } from '../../services'; +import { ReportingRequestHandlerContext, RunTaskFnFactory } from '../../types'; +import { CsvGenerator } from '../csv_searchsource/generate_csv/generate_csv'; +import { JobParamsDownloadCSV } from './types'; + +/* + * ImmediateExecuteFn receives the job doc payload because the payload was + * generated in the ScheduleFn + */ +export type ImmediateExecuteFn = ( + jobId: null, + job: JobParamsDownloadCSV, + context: ReportingRequestHandlerContext, + req: KibanaRequest +) => Promise; + +export const runTaskFnFactory: RunTaskFnFactory = function executeJobFactoryFn( + reporting, + parentLogger +) { + const config = reporting.getConfig(); + const logger = parentLogger.clone([CSV_SEARCHSOURCE_IMMEDIATE_TYPE, 'execute-job']); + + return async function runTask(jobId, immediateJobParams, context, req) { + const esClient = (await reporting.getEsClient()).asScoped(req); + const savedObjectsClient = context.core.savedObjects.client; + const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); + const searchService = await reporting.getSearchService(); + const searchSourceService = await searchService.searchSource.asScoped(req); + + const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( + uiSettingsClient + ); + + const job = { + objectType: 'immediate-search', + ...immediateJobParams, + }; + + const csv = new CsvGenerator( + job, + config, + esClient, + uiSettingsClient, + searchSourceService, + fieldFormatsRegistry, + new CancellationToken(), + logger + ); + + const result = await csv.generateData(); + + if (result.csv_contains_formulas) { + logger.warn(`CSV may contain formulas whose values have been escaped`); + } + + if (result.max_size_reached) { + logger.warn(`Max size reached: CSV output truncated to ${result.size} bytes`); + } + + const { warnings } = result; + if (warnings) { + warnings.forEach((warning) => { + logger.warning(warning); + }); + } + + return result; + }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/index.ts similarity index 75% rename from x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts rename to x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/index.ts index c3a0df9529a4d..9d915db4797b3 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/index.ts @@ -6,7 +6,7 @@ */ import { - CSV_FROM_SAVEDOBJECT_JOB_TYPE, + CSV_SEARCHSOURCE_IMMEDIATE_TYPE, LICENSE_TYPE_BASIC, LICENSE_TYPE_ENTERPRISE, LICENSE_TYPE_GOLD, @@ -15,7 +15,6 @@ import { LICENSE_TYPE_TRIAL, } from '../../../common/constants'; import { ExportTypeDefinition } from '../../types'; -import { createJobFnFactory, ImmediateCreateJobFn } from './create_job'; import { ImmediateExecuteFn, runTaskFnFactory } from './execute_job'; import { metadata } from './metadata'; @@ -23,17 +22,13 @@ import { metadata } from './metadata'; * These functions are exported to share with the API route handler that * generates csv from saved object immediately on request. */ -export { createJobFnFactory } from './create_job'; export { runTaskFnFactory } from './execute_job'; -export const getExportType = (): ExportTypeDefinition< - ImmediateCreateJobFn, - ImmediateExecuteFn -> => ({ +export const getExportType = (): ExportTypeDefinition => ({ ...metadata, - jobType: CSV_FROM_SAVEDOBJECT_JOB_TYPE, + jobType: CSV_SEARCHSOURCE_IMMEDIATE_TYPE, jobContentExtension: 'csv', - createJobFnFactory, + createJobFnFactory: null, runTaskFnFactory, validLicenses: [ LICENSE_TYPE_TRIAL, diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/metadata.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/metadata.ts new file mode 100644 index 0000000000000..c27b8484697dd --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/metadata.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CSV_SEARCHSOURCE_IMMEDIATE_TYPE } from '../../../common/constants'; + +export const metadata = { + id: CSV_SEARCHSOURCE_IMMEDIATE_TYPE, + name: CSV_SEARCHSOURCE_IMMEDIATE_TYPE, +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/types.d.ts new file mode 100644 index 0000000000000..276016dd61233 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/types.d.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TimeRangeParams } from '../common'; + +export interface FakeRequest { + headers: Record; +} + +export interface JobParamsDownloadCSV { + browserTimezone: string; + title: string; + searchSource: any; +} + +export interface SavedObjectServiceError { + statusCode: number; + error?: string; + message?: string; +} diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.ts index 1c0eb8f4f5b77..5eb6bcb0b42a9 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.ts @@ -47,12 +47,16 @@ export function enqueueJobFactory( throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); } + if (!exportType.createJobFnFactory) { + throw new Error(`Export type ${exportTypeId} is not an async job type!`); + } + const [createJob, { store }] = await Promise.all([ exportType.createJobFnFactory(reporting, logger), reporting.getPluginStartDeps(), ]); - const job = await createJob(jobParams, context, request); + const job = await createJob!(jobParams, context, request); const pendingReport = new Report({ jobtype: exportType.jobType, created_by: user ? user.username : false, diff --git a/x-pack/plugins/reporting/server/lib/export_types_registry.ts b/x-pack/plugins/reporting/server/lib/export_types_registry.ts index 5502692306319..890af43297751 100644 --- a/x-pack/plugins/reporting/server/lib/export_types_registry.ts +++ b/x-pack/plugins/reporting/server/lib/export_types_registry.ts @@ -6,8 +6,9 @@ */ import { isString } from 'lodash'; -import { getExportType as getTypeCsv } from '../export_types/csv'; -import { getExportType as getTypeCsvFromSavedObject } from '../export_types/csv_from_savedobject'; +import { getExportType as getTypeCsvDeprecated } from '../export_types/csv'; +import { getExportType as getTypeCsvFromSavedObject } from '../export_types/csv_searchsource_immediate'; +import { getExportType as getTypeCsv } from '../export_types/csv_searchsource'; import { getExportType as getTypePng } from '../export_types/png'; import { getExportType as getTypePrintablePdf } from '../export_types/printable_pdf'; import { CreateJobFn, ExportTypeDefinition } from '../types'; @@ -82,8 +83,9 @@ export function getExportTypesRegistry(): ExportTypesRegistry { const registry = new ExportTypesRegistry(); type CreateFnType = CreateJobFn; // can not specify params types because different type of params are not assignable to each other type RunFnType = any; // can not specify because ImmediateExecuteFn is not assignable to RunTaskFn - const getTypeFns: Array<() => ExportTypeDefinition> = [ + const getTypeFns: Array<() => ExportTypeDefinition> = [ getTypeCsv, + getTypeCsvDeprecated, getTypeCsvFromSavedObject, getTypePng, getTypePrintablePdf, diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 7d30ae78e5c84..6605ec37e57f8 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -118,11 +118,13 @@ export class ReportingPlugin const esqueue = await createQueueFactory(reportingCore, store, logger); // starts polling for pending jobs reportingCore.pluginStart({ + data: plugins.data, browserDriverFactory, savedObjects: core.savedObjects, uiSettings: core.uiSettings, esqueue, store, + esClient: core.elasticsearch.client, }); this.logger.debug('Start complete'); diff --git a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts similarity index 55% rename from x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts rename to x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts index 6d000cffb9195..55092b5236ce6 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts @@ -8,26 +8,17 @@ import { schema } from '@kbn/config-schema'; import { KibanaRequest } from 'src/core/server'; import { ReportingCore } from '../'; -import { createJobFnFactory } from '../export_types/csv_from_savedobject/create_job'; -import { runTaskFnFactory } from '../export_types/csv_from_savedobject/execute_job'; -import { - JobParamsPanelCsv, - JobParamsPanelCsvPost, -} from '../export_types/csv_from_savedobject/types'; +import { runTaskFnFactory } from '../export_types/csv_searchsource_immediate/execute_job'; +import { JobParamsDownloadCSV } from '../export_types/csv_searchsource_immediate/types'; import { LevelLogger as Logger } from '../lib'; import { TaskRunResult } from '../lib/tasks'; import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; -import { getJobParamsFromRequest } from './lib/get_job_params_from_request'; import { HandlerErrorFunction } from './types'; const API_BASE_URL_V1 = '/api/reporting/v1'; const API_BASE_GENERATE_V1 = `${API_BASE_URL_V1}/generate`; -export type CsvFromSavedObjectRequest = KibanaRequest< - JobParamsPanelCsv, - unknown, - JobParamsPanelCsvPost ->; +export type CsvFromSavedObjectRequest = KibanaRequest; /* * This function registers API Endpoints for immediate Reporting jobs. The API inputs are: @@ -47,43 +38,28 @@ export function registerGenerateCsvFromSavedObjectImmediate( const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; - /* - * CSV export with the `immediate` option does not queue a job with Reporting's ESQueue to run the job async. Instead, this does: - * - re-use the createJob function to build up es query config - * - re-use the runTask function to run the scan and scroll queries and capture the entire CSV in a result object. - */ + // This API calls run the SearchSourceImmediate export type's runTaskFn directly router.post( { - path: `${API_BASE_GENERATE_V1}/immediate/csv/saved-object/{savedObjectType}:{savedObjectId}`, + path: `${API_BASE_GENERATE_V1}/immediate/csv_searchsource`, validate: { - params: schema.object({ - savedObjectType: schema.string({ minLength: 5 }), - savedObjectId: schema.string({ minLength: 5 }), - }), body: schema.object({ - state: schema.object({}, { unknowns: 'allow' }), - timerange: schema.object({ - timezone: schema.string({ defaultValue: 'UTC' }), - min: schema.nullable(schema.oneOf([schema.number(), schema.string({ minLength: 5 })])), - max: schema.nullable(schema.oneOf([schema.number(), schema.string({ minLength: 5 })])), - }), + searchSource: schema.object({}, { unknowns: 'allow' }), + browserTimezone: schema.string({ defaultValue: 'UTC' }), + title: schema.string(), }), }, }, userHandler(async (user, context, req: CsvFromSavedObjectRequest, res) => { - const logger = parentLogger.clone(['savedobject-csv']); - const jobParams = getJobParamsFromRequest(req); - const createJob = createJobFnFactory(reporting, logger); + const logger = parentLogger.clone(['csv_searchsource_immediate']); const runTaskFn = runTaskFnFactory(reporting, logger); try { - // FIXME: no create job for immediate download - const payload = await createJob(jobParams, context, req); const { content_type: jobOutputContentType, content: jobOutputContent, size: jobOutputSize, - }: TaskRunResult = await runTaskFn(null, payload, context, req); + }: TaskRunResult = await runTaskFn(null, req.body, context, req); logger.info(`Job output size: ${jobOutputSize} bytes`); diff --git a/x-pack/plugins/reporting/server/routes/generation.ts b/x-pack/plugins/reporting/server/routes/generation.ts index c7ebd969fc01a..c4016e3f81edd 100644 --- a/x-pack/plugins/reporting/server/routes/generation.ts +++ b/x-pack/plugins/reporting/server/routes/generation.ts @@ -13,7 +13,7 @@ import { API_BASE_URL } from '../../common/constants'; import { LevelLogger as Logger } from '../lib'; import { enqueueJobFactory } from '../lib/enqueue_job'; import { registerGenerateFromJobParams } from './generate_from_jobparams'; -import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; +import { registerGenerateCsvFromSavedObjectImmediate } from './csv_searchsource_immediate'; import { HandlerFunction } from './types'; const esErrors = elasticsearchErrors as Record; diff --git a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts index 26f1a64a7ef63..7ae6159863970 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts @@ -8,7 +8,7 @@ // @ts-ignore import contentDisposition from 'content-disposition'; import { get } from 'lodash'; -import { CSV_JOB_TYPE_DEPRECATED } from '../../../common/constants'; +import { CSV_JOB_TYPE, CSV_JOB_TYPE_DEPRECATED } from '../../../common/constants'; import { ExportTypesRegistry, statuses } from '../../lib'; import { ReportDocument } from '../../lib/store'; import { TaskRunResult } from '../../lib/tasks'; @@ -34,11 +34,13 @@ const getTitle = (exportType: ExportTypeDefinition, title?: string): string => const getReportingHeaders = (output: TaskRunResult, exportType: ExportTypeDefinition) => { const metaDataHeaders: Record = {}; - if (exportType.jobType === CSV_JOB_TYPE_DEPRECATED) { + if (exportType.jobType === CSV_JOB_TYPE || exportType.jobType === CSV_JOB_TYPE_DEPRECATED) { const csvContainsFormulas = get(output, 'csv_contains_formulas', false); + const csvRowCount = get(output, 'csv_row_count', false); const maxSizedReach = get(output, 'max_size_reached', false); metaDataHeaders['kbn-csv-contains-formulas'] = csvContainsFormulas; + metaDataHeaders['kbn-csv-num-rows'] = csvRowCount; metaDataHeaders['kbn-max-size-reached'] = maxSizedReach; } diff --git a/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts b/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts deleted file mode 100644 index 8dce491e3df09..0000000000000 --- a/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { JobParamsPanelCsv } from '../../export_types/csv_from_savedobject/types'; -import { CsvFromSavedObjectRequest } from '../generate_from_savedobject_immediate'; - -export function getJobParamsFromRequest(request: CsvFromSavedObjectRequest): JobParamsPanelCsv { - const { savedObjectType, savedObjectId } = request.params; - const { timerange, state } = request.body; - - const post = timerange || state ? { timerange, state } : undefined; - - return { - savedObjectType, - savedObjectId, - post, - }; -} diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index ea8480ef3493d..5341db12f6548 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -12,7 +12,10 @@ jest.mock('../lib/create_queue'); import _ from 'lodash'; import * as Rx from 'rxjs'; -import { coreMock } from 'src/core/server/mocks'; +import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { fieldFormats } from 'src/plugins/data/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { dataPluginMock } from 'src/plugins/data/server/mocks'; import { ReportingConfig, ReportingCore } from '../'; import { featuresPluginMock } from '../../../features/server/mocks'; import { @@ -23,6 +26,7 @@ import { import { ReportingConfigType } from '../config'; import { ReportingInternalSetup, ReportingInternalStart } from '../core'; import { ReportingStore } from '../lib'; +import { setFieldFormats } from '../services'; import { createMockLevelLogger } from './create_mock_levellogger'; (initializeBrowserDriverFactory as jest.Mock< @@ -45,16 +49,23 @@ export const createMockPluginSetup = (setupMock?: any): ReportingInternalSetup = const logger = createMockLevelLogger(); -const createMockPluginStart = ( - mockReportingCore: ReportingCore, +const createMockReportingStore = () => ({} as ReportingStore); + +export const createMockPluginStart = ( + mockReportingCore: ReportingCore | undefined, startMock?: any ): ReportingInternalStart => { - const store = new ReportingStore(mockReportingCore, logger); + const store = mockReportingCore + ? new ReportingStore(mockReportingCore, logger) + : createMockReportingStore(); + return { browserDriverFactory: startMock.browserDriverFactory, esqueue: startMock.esqueue, + esClient: elasticsearchServiceMock.createClusterClient(), savedObjects: startMock.savedObjects || { getScopedClient: jest.fn() }, uiSettings: startMock.uiSettings || { asScopedToClient: () => ({ get: jest.fn() }) }, + data: startMock.data || dataPluginMock.createStartContract(), store, ...startMock, }; @@ -121,11 +132,18 @@ export const createMockReportingCore = async ( setupDepsMock: ReportingInternalSetup | undefined = undefined, startDepsMock: ReportingInternalStart | undefined = undefined ) => { - config = config || {}; + const mockReportingCore = ({ + getConfig: () => config, + getElasticsearchService: () => setupDepsMock?.elasticsearch, + getSearchService: () => startDepsMock?.data?.search, + } as unknown) as ReportingCore; if (!setupDepsMock) { setupDepsMock = createMockPluginSetup({}); } + if (!startDepsMock) { + startDepsMock = createMockPluginStart(mockReportingCore, {}); + } const context = coreMock.createPluginInitializerContext(createMockConfigSchema()); const core = new ReportingCore(logger); @@ -140,5 +158,12 @@ export const createMockReportingCore = async ( await core.pluginStart(startDepsMock); await core.pluginStartsUp(); + setFieldFormats({ + fieldFormatServiceFactory() { + const fieldFormatsRegistry = new fieldFormats.FieldFormatsRegistry(); + return Promise.resolve(fieldFormatsRegistry); + }, + }); + return core; }; diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index b395738ad4445..f84d2fbdf4712 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -80,13 +80,16 @@ export type RunTaskFnFactory = ( logger: LevelLogger ) => RunTaskFnType; -export interface ExportTypeDefinition { +export interface ExportTypeDefinition< + CreateJobFnType = CreateJobFn | null, + RunTaskFnType = RunTaskFn +> { id: string; name: string; jobType: string; jobContentEncoding?: string; jobContentExtension: string; - createJobFnFactory: CreateJobFnFactory; + createJobFnFactory: CreateJobFnFactory | null; // immediate job does not have a "create" phase runTaskFnFactory: RunTaskFnFactory; validLicenses: string[]; } diff --git a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap index ed2637d7a1bcb..150154fa996c5 100644 --- a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap +++ b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -13,6 +13,10 @@ Object { "available": true, "total": 0, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "enabled": true, "last7Days": Object { "PNG": Object { @@ -24,6 +28,10 @@ Object { "available": true, "total": 0, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "printable_pdf": Object { "app": Object { "dashboard": 0, @@ -75,6 +83,10 @@ Object { "available": true, "total": 0, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "enabled": true, "last7Days": Object { "PNG": Object { @@ -86,6 +98,10 @@ Object { "available": true, "total": 0, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "printable_pdf": Object { "app": Object { "dashboard": 0, @@ -166,6 +182,10 @@ Object { "available": true, "total": 1, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "enabled": true, "last7Days": Object { "PNG": Object { @@ -177,6 +197,10 @@ Object { "available": true, "total": 1, }, + "csv_searchsource": Object { + "available": true, + "total": 0, + }, "printable_pdf": Object { "app": Object { "canvas workpad": 1, diff --git a/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts b/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts index a750e9e196b20..9fc0141ab742e 100644 --- a/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts +++ b/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts @@ -6,7 +6,12 @@ */ import { uniq } from 'lodash'; -import { CSV_JOB_TYPE_DEPRECATED, PDF_JOB_TYPE, PNG_JOB_TYPE } from '../../common/constants'; +import { + CSV_JOB_TYPE, + CSV_JOB_TYPE_DEPRECATED, + PDF_JOB_TYPE, + PNG_JOB_TYPE, +} from '../../common/constants'; import { AvailableTotal, ExportType, FeatureAvailabilityMap, RangeStats } from './types'; function getForFeature( @@ -55,6 +60,7 @@ export const decorateRangeStats = ( // combine the known types with any unknown type found in reporting data const keysBasic = uniq([ + CSV_JOB_TYPE, CSV_JOB_TYPE_DEPRECATED, PNG_JOB_TYPE, ...Object.keys(rangeStatsBasic), diff --git a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap new file mode 100644 index 0000000000000..5df05de3b9fd9 --- /dev/null +++ b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a CSV export of a saved search panel 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +" +`; + +exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a filtered CSV export of a saved search panel 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +" +`; + +exports[`dashboard Reporting Download CSV Field Formatters and Scripted Fields Downloads a CSV export of a saved search panel 1`] = ` +"date,\\"_id\\",name,gender,value,year,\\"years_ago\\",\\"date_informal\\" +\\"Jan 1, 1984 @ 00:00:00.000\\",\\"1984-Fethany-F\\",Fethany,F,5,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" +\\"Jan 1, 1983 @ 00:00:00.000\\",\\"1983-Fethany-F\\",Fethany,F,\\"1,043\\",1983,\\"36.00000000000000000000\\",\\"Jan 1st 83\\" +\\"Jan 1, 1982 @ 00:00:00.000\\",\\"1982-Fethany-F\\",Fethany,F,780,1982,\\"37.00000000000000000000\\",\\"Jan 1st 82\\" +\\"Jan 1, 1981 @ 00:00:00.000\\",\\"1981-Fethany-F\\",Fethany,F,655,1981,\\"38.00000000000000000000\\",\\"Jan 1st 81\\" +\\"Jan 1, 1980 @ 00:00:00.000\\",\\"1980-Fethany-F\\",Fethany,F,702,1980,\\"39.00000000000000000000\\",\\"Jan 1st 80\\" +" +`; diff --git a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts index 72f07ef90d703..126e0a7006403 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts +++ b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts @@ -9,91 +9,139 @@ import { REPO_ROOT } from '@kbn/utils'; import expect from '@kbn/expect'; import fs from 'fs'; import path from 'path'; -import * as Rx from 'rxjs'; -import { filter, first, map, timeout } from 'rxjs/operators'; import { FtrProviderContext } from '../../../ftr_provider_context'; -const csvPath = path.resolve(REPO_ROOT, 'target/functional-tests/downloads/Ecommerce Data.csv'); - -// checks every 100ms for the file to exist in the download dir -// just wait up to 5 seconds -const getDownload$ = (filePath: string) => { - return Rx.interval(100).pipe( - map(() => fs.existsSync(filePath)), - filter((value) => value === true), - first(), - timeout(5000) - ); -}; - export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); const dashboardPanelActions = getService('dashboardPanelActions'); const log = getService('log'); const testSubjects = getService('testSubjects'); + const filterBar = getService('filterBar'); const find = getService('find'); - const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']); + const retry = getService('retry'); + const PageObjects = getPageObjects(['reporting', 'common', 'dashboard', 'timePicker']); + + const getCsvPath = (name: string) => + path.resolve(REPO_ROOT, `target/functional-tests/downloads/${name}.csv`); + + // checks every 100ms for the file to exist in the download dir + // just wait up to 5 seconds + const getDownload = (filePath: string) => { + return retry.tryForTime(5000, async () => { + expect(fs.existsSync(filePath)).to.be(true); + return fs.readFileSync(filePath).toString(); + }); + }; + + const clickActionsMenu = async (headingTestSubj: string) => { + const savedSearchPanel = await testSubjects.find('embeddablePanelHeading-' + headingTestSubj); + await dashboardPanelActions.toggleContextMenu(savedSearchPanel); + }; + + const clickDownloadCsv = async () => { + log.debug('click "More"'); + await dashboardPanelActions.clickContextMenuMoreItem(); + + const actionItemTestSubj = 'embeddablePanelAction-downloadCsvReport'; + await testSubjects.existOrFail(actionItemTestSubj); // wait for the full panel to display or else the test runner could click the wrong option! + log.debug('click "Download CSV"'); + await testSubjects.click(actionItemTestSubj); + await testSubjects.existOrFail('csvDownloadStarted'); // validate toast panel + }; describe('Download CSV', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); - await esArchiver.loadIfNeeded('reporting/ecommerce'); - await esArchiver.loadIfNeeded('reporting/ecommerce_kibana'); await browser.setWindowSize(1600, 850); }); - after('clean up archives and previous file download', async () => { - await esArchiver.unload('reporting/ecommerce'); - await esArchiver.unload('reporting/ecommerce_kibana'); - }); - afterEach('remove download', () => { try { - fs.unlinkSync(csvPath); + fs.unlinkSync(getCsvPath('Ecommerce Data')); } catch (e) { // it might not have been there to begin with } }); - it('Downloads a CSV export of a saved search panel', async function () { - await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); - const savedSearchPanel = await testSubjects.find('embeddablePanelHeading-EcommerceData'); - await dashboardPanelActions.toggleContextMenu(savedSearchPanel); + describe('E-Commerce Data', () => { + before(async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + }); + after(async () => { + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); - const actionExists = await testSubjects.exists('embeddablePanelAction-downloadCsvReport'); - if (!actionExists) { - await dashboardPanelActions.clickContextMenuMoreItem(); - } - await testSubjects.existOrFail('embeddablePanelAction-downloadCsvReport'); // wait for the full panel to display or else the test runner could click the wrong option! - await testSubjects.click('embeddablePanelAction-downloadCsvReport'); - await testSubjects.existOrFail('csvDownloadStarted'); // validate toast panel + it('Downloads a CSV export of a saved search panel', async function () { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); + await clickActionsMenu('EcommerceData'); + await clickDownloadCsv(); + + const csvFile = await getDownload(getCsvPath('Ecommerce Data')); + expectSnapshot(csvFile).toMatch(); + }); - const fileExists = await getDownload$(csvPath).toPromise(); - expect(fileExists).to.be(true); + it('Downloads a filtered CSV export of a saved search panel', async function () { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); - // no need to validate download contents, API Integration tests do that some different variations + // add a filter + await filterBar.addFilter('currency', 'is', 'EUR'); + + await clickActionsMenu('EcommerceData'); + await clickDownloadCsv(); + + const csvFile = await getDownload(getCsvPath('Ecommerce Data')); + expectSnapshot(csvFile).toMatch(); + }); + + it('Gets the correct filename if panel titles are hidden', async () => { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard Hidden Panel Titles'); + const savedSearchPanel = await find.byCssSelector( + '[data-test-embeddable-id="94eab06f-60ac-4a85-b771-3a8ed475c9bb"]' + ); // panel title is hidden + await dashboardPanelActions.toggleContextMenu(savedSearchPanel); + + await clickDownloadCsv(); + await testSubjects.existOrFail('csvDownloadStarted'); + + const csvFile = await getDownload(getCsvPath('Ecommerce Data')); // file exists with proper name + expect(csvFile).to.not.be(null); + }); }); - it('Gets the correct filename if panel titles are hidden', async () => { - await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard Hidden Panel Titles'); - const savedSearchPanel = await find.byCssSelector( - '[data-test-embeddable-id="94eab06f-60ac-4a85-b771-3a8ed475c9bb"]' - ); // panel title is hidden - await dashboardPanelActions.toggleContextMenu(savedSearchPanel); - - const actionExists = await testSubjects.exists('embeddablePanelAction-downloadCsvReport'); - if (!actionExists) { - await dashboardPanelActions.clickContextMenuMoreItem(); - } - await testSubjects.existOrFail('embeddablePanelAction-downloadCsvReport'); - await testSubjects.click('embeddablePanelAction-downloadCsvReport'); - await testSubjects.existOrFail('csvDownloadStarted'); + describe('Field Formatters and Scripted Fields', () => { + before(async () => { + await esArchiver.load('reporting/hugedata'); + }); + after(async () => { + await esArchiver.unload('reporting/hugedata'); + }); + + it('Downloads a CSV export of a saved search panel', async () => { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.loadSavedDashboard('names dashboard'); + await PageObjects.timePicker.setAbsoluteRange( + 'Jan 01, 1980 @ 00:00:00.000', + 'Dec 31, 1984 @ 23:59:59.000' + ); + + await PageObjects.common.sleep(1000); + + await filterBar.addFilter('name.keyword', 'is', 'Fethany'); + + await PageObjects.common.sleep(1000); + + await clickActionsMenu('namessearch'); + await clickDownloadCsv(); - const fileExists = await getDownload$(csvPath).toPromise(); // file exists with proper name - expect(fileExists).to.be(true); + const csvFile = await getDownload(getCsvPath('namessearch')); + expectSnapshot(csvFile).toMatch(); + }); }); }); } diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 43771b00525cc..3c2fd087cfd66 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -2,39 +2,48 @@ exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Shoes\\"\\",\\"\\"Men's Clothing\\"\\",\\"\\"Women's Accessories\\"\\",\\"\\"Men's Accessories\\"\\"]\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0687606876\\"\\",\\"\\"ZO0290502905\\"\\",\\"\\"ZO0126701267\\"\\",\\"\\"ZO0308503085\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Women's Shoes\\"\\",\\"\\"Women's Clothing\\"\\"]\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0006400064\\"\\",\\"\\"ZO0150601506\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0638206382\\"\\",\\"\\"ZO0038800388\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0297602976\\"\\",\\"\\"ZO0565605656\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0561405614\\"\\",\\"\\"ZO0281602816\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Shoes\\"\\",\\"\\"Men's Clothing\\"\\"]\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0385003850\\"\\",\\"\\"ZO0408604086\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0505605056\\"\\",\\"\\"ZO0513605136\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0276702767\\"\\",\\"\\"ZO0291702917\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0046600466\\"\\",\\"\\"ZO0050800508\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Clothing\\"\\",\\"\\"Men's Shoes\\"\\"]\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0455604556\\"\\",\\"\\"ZO0680806808\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Women's Clothing\\"\\",\\"\\"Women's Shoes\\"\\"]\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0229002290\\"\\",\\"\\"ZO0674406744\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0529905299\\"\\",\\"\\"ZO0617006170\\"\\"]\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Shoes\\"\\",\\"\\"Men's Clothing\\"\\",\\"\\"Women's Accessories\\"\\",\\"\\"Men's Accessories\\"\\"]\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0687606876\\"\\",\\"\\"ZO0290502905\\"\\",\\"\\"ZO0126701267\\"\\",\\"\\"ZO0308503085\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Women's Shoes\\"\\",\\"\\"Women's Clothing\\"\\"]\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0006400064\\"\\",\\"\\"ZO0150601506\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0638206382\\"\\",\\"\\"ZO0038800388\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0297602976\\"\\",\\"\\"ZO0565605656\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0561405614\\"\\",\\"\\"ZO0281602816\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Shoes\\"\\",\\"\\"Men's Clothing\\"\\"]\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0385003850\\"\\",\\"\\"ZO0408604086\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0505605056\\"\\",\\"\\"ZO0513605136\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0276702767\\"\\",\\"\\"ZO0291702917\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0046600466\\"\\",\\"\\"ZO0050800508\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Men's Clothing\\"\\",\\"\\"Men's Shoes\\"\\"]\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0455604556\\"\\",\\"\\"ZO0680806808\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Women's Clothing\\"\\",\\"\\"Women's Shoes\\"\\"]\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0229002290\\"\\",\\"\\"ZO0674406744\\"\\"]\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"[\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\",\\"\\"Dec 31, 2016 @ 00:00:00.000\\"\\"]\\",\\"[\\"\\"ZO0529905299\\"\\",\\"\\"ZO0617006170\\"\\"]\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; exports[`discover Discover Generate CSV: new search generates a report with data 1`] = ` -"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" +\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,,\\" - \\" " `; diff --git a/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz b/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz index 83da642be87622f3b3d7a7b0b92f62e88fed5977..e5fb8a73234e4fca80958028dc282642ece8b96a 100644 GIT binary patch literal 33885 zcmV)tK$pKCiwFo)GcaHP17u-zVJ>QOZ*Bn8U0HJ@HQINMx|sMXGx2320sQgR#l_|N z@jk!2zPOw&Czo&Vz;D_70gwCvf54x`6wgkUi&=4Vt*yemd&?T|vA5U475fSNQ+wtFQhz|JBs;Po`r_%#4hbVFa5!9$BvC zNQ|eNkeQyEsrWN5?y$LA*mkdRE659hhx-=Uooiqv#n0Jq`Si!}r+l*hK3`{7Rl|OE z68-PbKmKr4iGA>d4MgtL=ssJo^Kx;yz2d30p@0~(+E$9s6(&FviiufLhk-(Oy@%ZL2U`^(?*as}VLJFr@oYxwI| zxC6z9kMEt3?=PP|z-eb!aPW`a$M=`-FX7C*Ha2&pvNpH}PRxpYK3%;nmv@y+`1JSq zI^1m^-Mg+nt|rSeuRqq8;%C$f_o)&HK2$HteZ;ruKHTSU!(#0|yO-uZ;hWihaIa|l zr0tt|fBC_QIbY*5uYbkAoK!#Mvme~!p+zrIYH0VK((XGa0QZ?*?tiXT=0J&R9l6{) z^ueo1>ta23#)F8gYQxw&U%zR%f;ODs#_pco)o^x*!lGf zJkE=J-k~=+@D)xszge%#Rc$3sEm6BC%Li1ZYx=aOZ;ca`_B9UI`qwyKX`}aWt(%Q= z&ouS${L}smc5SJ;*6*|Xx;@Vx?OF$7KirLL`?=4`>~2+^ts!!kkT>Ltc>aNIAGYKL zkF4+YG^u{b*1!)RQLggoKg#;jWm()5)dO$W>-+1kzn(8A+5C37T3<`WNPYkMcCj(t zue1C6ucz7ScD&5W>B?O&&Q|%~;iB4qJ-s;;_51I?zxZx>@yjnLaua2zEx+!+3iO=L zk-OWG7F>)jK>2_D3nKNG4_7;vgpSf(b)OZBIhg96AG?0;s4Cxgh;Q{p`E<`|JG;%s z^L%$KySXXzn{0h}w9K<9y5jGalYgQ_i193&ukxoi$D8BYf$!!e?RfT<_uI04&F!@0 z!~Xj!p+&`A{uW=`#w-qA==SUnHGO&Jf_IK}oQ)rybA36BJaj?l`d22eq>>T-b)GL) z*J3QJq0&)FnvhE3!wtvOfJ zV|UkY>fJ`=niOU4%3}3j50lS1Xf<5xO!e56^K6{YPd{)8#4baX+W-EKx5a9`yn#;Q z_>EN`5@?mvFVHM79ei%~uwMEg$A3>pzhwn|Pi^A$qmEzdRNeWSZL_`C9{INOl;+I0 zSoJ4ozDMU*Prt}-vHQ4K&MwLvm^}27=f70f^8}#VpzQ8C8{(g8Is7Plj(U-YS36nW z-OmAxZ+C{)y#4u+!@u|cI{2D8@;K}{+zA(9HJ##oFRk&}UGgko*xYw{dGtGfD^?HL zy!evU&bsjxwO@Vi`aFI%n?Sb*k&W+icfp_YbskSwiS<|aYR~fSo=4m-SH-4-S}*T? zm#p%#$X6T99B1W6=)J%eyw6+RF8}jCWig!>3)g`iF_p{Tzo}uWgg?U_2es)LI?x$o zjNJ0ESmS zxAuy`{0)7Hqt~~^^uRst+P@!BZ=XH&bO?u9zL9jkSpDmlQxvY9%-BAi8SU85Xz~Dn zF4m(1y7QvU*qd$zc7`~5u?@aF!MC}=k0c{uBKCrSif}x2$g*K z;x+>ha|gEWk{eIkuh>sDx&t3ETk_`5G~BiGu;pUg@)^%FN!e_a3qePM5j8SdrbmR3 zF%{J085?_Be%_5qT23+7{5(YeDF^>v=FJ}VS>p3zXIW<^KhJmkFBp`m@7ws%`jz^f zVV!k7)0w{@oc9Vr{X#egdxj%!!h6aaGkYZkiSWkM8a{fPKQ0%av(ejzx80>>0^Zgo zAF3x25RbkitXQPgrAC^nKez*1d+MG&mT zBwn>h99SU2aj>M)IHGQ}AOtWF4X7v)9~g8Y0C8PNoZ-SQ?yIdpL2;C`9I*C@#1(T%KirtPS6u z0H`?69t27QP=<3ul;PCaCSjn=15_)1eGGk2d@mSld?3RsvA+~(#hPFktpQnKzW6O) z6w|)>`$miaXu#fu)j;EomfGqjW|VYckqFvs)-znQS;!Wxlo+>LAg78q<3gV)CWlF+ zfl0In6Ih=jmMJSJ6~MBZRMf|v0_DO>ccP#{4NDyxMt!U7L95E(XYuajH@>eM`& z_pDU&y@B^8R2ChzHpDOpb*xbhq-ZBvg_(vqz|(iC!O0NJVrj{V2H&orOO(1v9DF@t z@?3+1D_*f8u?p!GH;hsU02wouGEY`UcYza6gHxQZ3gE;Uqudz61(kvd-K6c3b;1&u z11isZCZZ_9@Odb8VD+6}011vmB@|uifS#CCPE4<%4uqs?PSoa>I#blaK-k8MF=ejn-ypfC0bG@ zv_3CxZY3v^2CZo23ZiAWlAKyAwIGyHpEY)&TorMD?47wk9*2s94+5AJP^Be%|t`mIhKOTGx#e<3ws*Ev$TOzF|diJK++fu9k zxqA>SsV(JNf__oPEwv4>e7>qB>i+mCn|$t_y*nvF=?0}OgoY4ETdt`U=T%{~MBpDk zEeD`rAVkO>hcV=Z&TBD!=-GFH1R?g$G4a5tB^o}NW`f3-A5HGLDx~^m4j{qnaPo_r zo-J^36LMF>8TCp4RGf1U12r7KzIa^T6@3q;RzeJ4vkvTu$Z$ zSW*)uHCN!Kq(#)uBMhx%Ws;y3N3KqwH4t{?RO_Z#_pMqWLJ%yiaX3}tR`w1R$`C?p z7}G9AGPvRh{7JZmQ<1#7UEcSuTzhNg_!53x3B$q1Q%^!-x$* zuRiswQ=eXgKE-1crAr}Isujd&Ek|B zVj#8wcisex`?6PUr20V8vfoS}N)RwY#kG_5Gg{nqKskuM~P`d#X89?yaK4Sl-g(t5e>vLzEr5U z3v8oC6y@xBOu~r}3jT&M6ON?hJO3SSE6l!-h zb1(^1k?txCm6D7B4V6Z6Ym_It>1tSh;7~E872{xr7TKsLwh>;s&<NWvakc@BbQ!;z^o0|@vA znz{9bf$dQC-k0e+0hSb0Yr?F+vMb)qe{$Q2XRj6Ow&#kEN`~WB$T4KrQW=G7&w0`@ zs*_-lB||Hci-yr++5%YCVu7|+#xvvDJBhcAf%!ymMO$JRE}##B8jh1DsA3-S&z=R}?xvjx|@*5?sQ)Nl0lYiwz(jE$;e`b3lSn|2K>k zqgf)T;?yb()nHbzNP<+HuL>ijfGQY8C6UT*-f1=oOBLmIf^c*6;}D3O90O#wCq*60~d^$rrY!bczaPL4i=f}DYLg***V zasE9Blop&@4K7Pb0zTdo;dEB}@wiTq6OHrkC_*SD3Uq;SELW4n7}{hFvXeSBmI|ym zXLSNBN(^uYMif>yaL-l~-txyb!knJh=nHOmHkjSvh6~cO%(@4nPGUfj0;8yOaR4Kx zr4Kgh!D?Ot%oykh1vQy5eBULR)odtEmwbmx_jd&qtwr@k|?4*~@Xiz1?yg zB2drzy7T6^CGYA)5}4xD={QW3putf|rNyPzRdnQn|5TOXhQVooN zC@Bb+tcjSn&Z-Rxl?t#Z5_J+Vf_wS`kZ^YzTe?)6D@0(^*CV1^txwy>Q`H zjNzwYHf}z_t`hN%KD4a_=oN4XO2IUVz}@GY>4vU$07wN`yt5Aj#&9VHh<<=`Dc004 z@ACGodHcS%EjfvoAd-WMXSWZpHpn5^<7+U-Dh<)|E-xs-ai|PoLK57- zglHTyP3Qz5+N0tT0V{x)sza$te{2;MLi2$vHcao zT2C$~*ybhLt%vfY!>H(^sj!On>*1U-uDWUjlh6q=b!O2=8`Uvsz>0QPL9hl=gIt?o z0xlYDhrt~O2eLqlv&19=Jdvh&Vn7U4#Snq(^l70zWiqU*wY3w$6-l#B42M}xnB<%( z36Y_1m6YzXrb*C>bX}*=f`G>mMX~AuYezlNPG@0s?}LYd&9EtxQV8%@&>M2__|1HS zcL}U^tg!dN!vIjYqcg)D!wnV6aCN3ewPS$24;_Xyic88Fu0c*Mu7c&E@0~1_i9n^; zj3W-I@Ln8-NDf^eF_OcNXY9V4DJCKjRB<8Ui5+nUva&C#Ro_bW3U*`^Nnnaos31Q; z->eM*pALbuIg?JcQZ;&)E#m!o98xGkD8s-klgw&OwE_)mVCBmjw~~xW090HE7=~#O zi5Q*+r#KH4#Az5?-vCZ|+4n9%C_zZ0B$hL991=8=dFCi}vgE%*>T^ENdrq&{LWJ-d z#1;w6;gtfesBor|A(XG8z&x>528cTLfz2U_u2Kq#;EL6**PvVi(MkbU6k~8Agj8!V z8}5RneQ&qxL3F(vQ*zipJERMHLtvH)P3NQQf-SOARq7JKtgqH1SgY0*EQ4UzwW z3@cT=WuAtY#rBr@DOxs+8lD=nVln{4K!^Zd16eJvvd4Tr@7*Fnh5%f{sm?@E69nY3 z?miFZF9uRZP@Chr{}2ge7``#m8m`;k3kjSMA;5;QSo%i42BBaf4WouY2#K3QX(I9bO4cGC1*yXv1-JSp}vk zeRI^hn$8EZ-VR|9={7v*HjFyq${*muN+F43`AxV~CrQ@V0oTC7?G$juhTCDd1~JdCc3cDSTd!t_sP9?sC%_Vt zG0r(dZx6pb9b#8YS~@`!m|-lbMsZDVJ`P3qm?qXJGt(B1wT^lPs+2>BS%ynojfgAP?mlGny=cNQr zFF~^ySR_4j4VZRD8_VA3E0=*8xSW6qa-*3LmI~rocD)lr6p4_EjC(>zF$4V})0F>z zdvBv#$B}CbKhXt>Wc|LteGl2zBs*3lK$bJ3JpCoRx09J{Znp5Tx~dF(IZmR%0AqR` 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˾C_Vojy7lQE09P4q(~ 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

f^VA3z+;f_!$%;Zz)J#6V%kmwclVlopxg2ynoE{ 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 literal 33745 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 { const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ - jobParams: JOB_PARAMS_RISON, + jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED, })) as supertest.Response; expect(resText).to.match(/"jobtype":"csv"/); expect(resStatus).to.eql(200); @@ -71,7 +71,7 @@ export default function ({ getService }: FtrProviderContext) { it('Accepts jobParams in query string', async () => { const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInQueryString( - JOB_PARAMS_RISON + JOB_PARAMS_RISON_CSV_DEPRECATED )) as supertest.Response; expect(resText).to.match(/"jobtype":"csv"/); expect(resStatus).to.eql(200); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_saved_search.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_saved_search.ts deleted file mode 100644 index bb70924f67b75..0000000000000 --- a/x-pack/test/reporting_api_integration/reporting_and_security/csv_saved_search.ts +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import supertest from 'supertest'; -import * as fixtures from '../fixtures'; -import { FtrProviderContext } from '../ftr_provider_context'; - -interface GenerateOpts { - timerange?: { - timezone: string; - min?: number | string | Date; - max?: number | string | Date; - }; - state: any; -} - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const supertestSvc = getService('supertest'); - const reportingAPI = getService('reportingAPI'); - - const generateAPI = { - getCsvFromSavedSearch: async ( - id: string, - { timerange, state }: GenerateOpts, - isImmediate = true - ) => { - return await supertestSvc - .post(`/api/reporting/v1/generate/${isImmediate ? 'immediate/' : ''}csv/saved-object/${id}`) - .set('kbn-xsrf', 'xxx') - .send({ timerange, state }); - }, - }; - - describe('Generation from Saved Search ID', () => { - after(async () => { - await reportingAPI.deleteAllReports(); - }); - - describe('Saved Search Features', () => { - it('With filters and timebased data, explicit UTC format', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/logs'); - await esArchiver.load('logstash_functional'); - - const res = (await generateAPI.getCsvFromSavedSearch( - 'search:d7a79750-3edd-11e9-99cc-4d80163ee9e7', - { - timerange: { - timezone: 'UTC', - min: '2015-09-19T10:00:00.000Z', - max: '2015-09-21T10:00:00.000Z', - }, - state: {}, - } - )) as supertest.Response; - const { status: resStatus, text: resText, type: resType } = res; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_TIMEBASED_UTC); - - await esArchiver.unload('reporting/logs'); - await esArchiver.unload('logstash_functional'); - }); - - it('With filters and timebased data, default to UTC', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/logs'); - await esArchiver.load('logstash_functional'); - - const res = (await generateAPI.getCsvFromSavedSearch( - 'search:d7a79750-3edd-11e9-99cc-4d80163ee9e7', - { - // @ts-expect-error: timerange.timezone is missing from post params - timerange: { - min: '2015-09-19T10:00:00.000Z', - max: '2015-09-21T10:00:00.000Z', - }, - state: {}, - } - )) as supertest.Response; - const { status: resStatus, text: resText, type: resType } = res; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_TIMEBASED_UTC); - - await esArchiver.unload('reporting/logs'); - await esArchiver.unload('logstash_functional'); - }); - - it('With filters and timebased data, custom timezone', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/logs'); - await esArchiver.load('logstash_functional'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:d7a79750-3edd-11e9-99cc-4d80163ee9e7', - { - timerange: { - timezone: 'America/Phoenix', - min: '2015-09-19T10:00:00.000Z', - max: '2015-09-21T10:00:00.000Z', - }, - state: {}, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_TIMEBASED_CUSTOM); - - await esArchiver.unload('reporting/logs'); - await esArchiver.unload('logstash_functional'); - }); - - it('With filters and non-timebased data', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/sales'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:71e3ee20-3f99-11e9-b8ee-6b9604f2f877', - { - state: {}, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_TIMELESS); - - await esArchiver.unload('reporting/sales'); - }); - - it('With scripted fields and field formatters', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/scripted_small2'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:a6d51430-ace2-11ea-815f-39e12f89a8c2', - { - timerange: { - timezone: 'UTC', - min: '1979-01-01T10:00:00Z', - max: '1981-01-01T10:00:00Z', - }, - state: {}, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_SCRIPTED); - - await esArchiver.unload('reporting/scripted_small2'); - }); - - it('Formatted date_nanos data, UTC timezone', async () => { - await esArchiver.load('reporting/nanos'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:e4035040-a295-11e9-a900-ef10e0ac769e', - { - state: {}, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_NANOS); - - await esArchiver.unload('reporting/nanos'); - }); - - it('Formatted date_nanos data, custom time zone', async () => { - await esArchiver.load('reporting/nanos'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:e4035040-a295-11e9-a900-ef10e0ac769e', - { - state: {}, - timerange: { timezone: 'America/New_York' }, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_NANOS_CUSTOM); - - await esArchiver.unload('reporting/nanos'); - }); - }); - - describe('API Features', () => { - it('Return a 404', async () => { - const { body } = (await generateAPI.getCsvFromSavedSearch('search:gobbledygook', { - timerange: { timezone: 'UTC', min: 63097200000, max: 126255599999 }, - state: {}, - })) as supertest.Response; - const expectedBody = { - error: 'Not Found', - message: 'Saved object [search/gobbledygook] not found', - statusCode: 404, - }; - expect(body).to.eql(expectedBody); - }); - - it('Return 400 if time range param is needed but missing', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/logs'); - await esArchiver.load('logstash_functional'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:d7a79750-3edd-11e9-99cc-4d80163ee9e7', - { state: {} } - )) as supertest.Response; - - expect(resStatus).to.eql(400); - expect(resType).to.eql('application/json'); - const { message: errorMessage } = JSON.parse(resText); - expect(errorMessage).to.eql( - 'Time range params are required for index pattern [logstash-*], using time field [@timestamp]' - ); - - await esArchiver.unload('reporting/logs'); - await esArchiver.unload('logstash_functional'); - }); - - it('Stops at Max Size Reached', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/hugedata'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:f34bf440-5014-11e9-bce7-4dabcb8bef24', - { - timerange: { - timezone: 'UTC', - min: '1960-01-01T10:00:00Z', - max: '1999-01-01T10:00:00Z', - }, - state: {}, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_HUGE); - - await esArchiver.unload('reporting/hugedata'); - }); - }); - - describe('Merge user state into the query', () => { - it('for query', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/scripted_small2'); - - const params = { - searchId: 'search:a6d51430-ace2-11ea-815f-39e12f89a8c2', - postPayload: { - timerange: { timezone: 'UTC', min: '1979-01-01T10:00:00Z', max: '1981-01-01T10:00:00Z' }, // prettier-ignore - state: { query: { bool: { filter: [ { bool: { filter: [ { bool: { minimum_should_match: 1, should: [{ query_string: { fields: ['name'], query: 'Fel*' } }] } } ] } } ] } } }, // prettier-ignore - }, - isImmediate: true, - }; - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - params.searchId, - params.postPayload, - params.isImmediate - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_SCRIPTED_REQUERY); - - await esArchiver.unload('reporting/scripted_small2'); - }); - - it('for sort', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/hugedata'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - 'search:f34bf440-5014-11e9-bce7-4dabcb8bef24', - { - timerange: { - timezone: 'UTC', - min: '1979-01-01T10:00:00Z', - max: '1981-01-01T10:00:00Z', - }, - state: { sort: [{ name: { order: 'asc', unmapped_type: 'boolean' } }] }, - } - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_SCRIPTED_RESORTED); - - await esArchiver.unload('reporting/hugedata'); - }); - - it('for docvalue_fields', async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/ecommerce'); - await esArchiver.load('reporting/ecommerce_kibana'); - - const params = { - searchId: 'search:6091ead0-1c6d-11ea-a100-8589bb9d7c6b', - postPayload: { - timerange: { - min: '2019-05-28T00:00:00Z', - max: '2019-06-26T00:00:00Z', - timezone: 'UTC', - }, - state: { - sort: [ - { order_date: { order: 'desc', unmapped_type: 'boolean' } }, - { order_id: { order: 'asc', unmapped_type: 'boolean' } }, - ], - docvalue_fields: [ - { field: 'customer_birth_date', format: 'date_time' }, - { field: 'order_date', format: 'date_time' }, - { field: 'products.created_on', format: 'date_time' }, - ], - query: { - bool: { - must: [], - filter: [ - { match_all: {} }, - { match_all: {} }, - { - range: { - order_date: { - gte: '2019-05-28T00:00:00.000Z', - lte: '2019-06-26T00:00:00.000Z', - format: 'strict_date_optional_time', - }, - }, - }, - ], - should: [], - must_not: [], - }, - }, - }, - }, - isImmediate: true, - }; - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCsvFromSavedSearch( - params.searchId, - params.postPayload, - params.isImmediate - )) as supertest.Response; - - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expect(resText).to.eql(fixtures.CSV_RESULT_DOCVALUE); - - await esArchiver.unload('reporting/ecommerce'); - await esArchiver.unload('reporting/ecommerce_kibana'); - }); - }); - }); -} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts new file mode 100644 index 0000000000000..7f2a13b7cfe45 --- /dev/null +++ b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts @@ -0,0 +1,344 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import supertest from 'supertest'; +import { JobParamsDownloadCSV } from '../../../plugins/reporting/server/export_types/csv_searchsource_immediate/types'; +import { FtrProviderContext } from '../ftr_provider_context'; + +const getMockJobParams = (obj: Partial): JobParamsDownloadCSV => ({ + title: `Mock CSV Title`, + ...(obj as any), +}); + +// eslint-disable-next-line import/no-default-export +export default function ({ getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const esArchiver = getService('esArchiver'); + const supertestSvc = getService('supertest'); + const reportingAPI = getService('reportingAPI'); + + const generateAPI = { + getCSVFromSearchSource: async (job: JobParamsDownloadCSV) => { + return await supertestSvc + .post(`/api/reporting/v1/generate/immediate/csv_searchsource`) + .set('kbn-xsrf', 'xxx') + .send(job); + }, + }; + + describe('CSV generation from SearchSource', () => { + before(async () => { + await kibanaServer.uiSettings.update({ + 'csv:quoteValues': false, + 'dateFormat:tz': 'UTC', + defaultIndex: 'logstash-*', + }); + }); + after(async () => { + await reportingAPI.deleteAllReports(); + }); + + describe('date formatting', () => { + before(async () => { + // load test data that contains a saved search and documents + await esArchiver.load('reporting/logs'); + await esArchiver.load('logstash_functional'); + }); + after(async () => { + await esArchiver.unload('reporting/logs'); + await esArchiver.unload('logstash_functional'); + }); + + it('With filters and timebased data, explicit UTC format', async () => { + const res = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + browserTimezone: 'UTC', + searchSource: { + fields: ['@timestamp', 'clientip', 'extension'], + filter: [ + { + range: { + '@timestamp': { + gte: '2015-09-20T10:19:40.307Z', + lt: '2015-09-20T10:26:56.221Z', + }, + }, + }, + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: '2015-01-12T07:00:55.654Z', + lte: '2016-01-29T21:08:10.881Z', + }, + }, + }, + ], + index: 'logstash-*', + query: { language: 'kuery', query: '' }, + sort: [{ '@timestamp': 'desc' }], + }, + }) + )) as supertest.Response; + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + }); + + it('With filters and timebased data, default to UTC', async () => { + const res = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + fields: ['@timestamp', 'clientip', 'extension'], + filter: [ + { + range: { + '@timestamp': { + gte: '2015-09-20T10:19:40.307Z', + lt: '2015-09-20T10:26:56.221Z', + }, + }, + }, + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: '2015-01-12T07:00:55.654Z', + lte: '2016-01-29T21:08:10.881Z', + }, + }, + }, + ], + index: 'logstash-*', + query: { language: 'kuery', query: '' }, + sort: [{ '@timestamp': 'desc' }], + }, + }) + )) as supertest.Response; + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + }); + + it('With filters and timebased data, custom timezone (Phoenix)', async () => { + const res = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + browserTimezone: 'America/Phoenix', + searchSource: { + fields: ['@timestamp', 'clientip', 'extension'], + filter: [ + { + range: { + '@timestamp': { + gte: '2015-09-20T10:19:40.307Z', + lt: '2015-09-20T10:26:56.221Z', + }, + }, + }, + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: '2015-01-12T07:00:55.654Z', + lte: '2016-01-29T21:08:10.881Z', + }, + }, + }, + ], + index: 'logstash-*', + query: { language: 'kuery', query: '' }, + sort: [{ '@timestamp': 'desc' }], + }, + }) + )) as supertest.Response; + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + }); + + it('Formatted date_nanos data, UTC timezone', async () => { + await esArchiver.load('reporting/nanos'); + + const res = await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + version: true, + index: '907bc200-a294-11e9-a900-ef10e0ac769e', + sort: [{ date: 'desc' }], + fields: ['date', 'message'], + filter: [], + }, + }) + ); + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/nanos'); + }); + + it('Formatted date_nanos data, custom timezone (New York)', async () => { + await esArchiver.load('reporting/nanos'); + + const res = await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + browserTimezone: 'America/New_York', + searchSource: { + query: { query: '', language: 'kuery' }, + version: true, + index: '907bc200-a294-11e9-a900-ef10e0ac769e', + sort: [{ date: 'desc' }], + fields: ['date', 'message'], + filter: [], + }, + }) + ); + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/nanos'); + }); + }); + + describe('non-timebased', () => { + it('Handle _id and _index columns', async () => { + await esArchiver.load('reporting/nanos'); + + const res = await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + version: true, + index: '907bc200-a294-11e9-a900-ef10e0ac769e', + sort: [{ date: 'desc' }], + fields: ['date', 'message', '_id', '_index'], + filter: [], + }, + }) + ); + const { status: resStatus, text: resText, type: resType } = res; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/nanos'); + }); + + it('With filters and non-timebased data', async () => { + // load test data that contains a saved search and documents + await esArchiver.load('reporting/sales'); + + const { + status: resStatus, + text: resText, + type: resType, + } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + version: true, + index: 'timeless-sales', + sort: [{ power: 'asc' }], + fields: ['name', 'power'], + filter: [ + { + range: { power: { gte: 1, lt: null } }, + }, + ], + }, + }) + )) as supertest.Response; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/sales'); + }); + }); + + describe('validation', () => { + it('Return a 404', async () => { + const { body } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + index: 'gobbledygook', + }, + }) + )) as supertest.Response; + const expectedBody = { + error: 'Not Found', + message: 'Saved object [index-pattern/gobbledygook] not found', + statusCode: 404, + }; + expect(body).to.eql(expectedBody); + }); + + it(`Searches "huge" data, stops at Max Size Reached`, async () => { + // load test data that contains a saved search and documents + await esArchiver.load('reporting/hugedata'); + + const { + status: resStatus, + text: resText, + type: resType, + } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'lucene' }, + version: true, + sort: [{ date: 'desc' }], + index: '89655130-5013-11e9-bce7-4dabcb8bef24', + fields: [ + '_id', + 'date', + 'name', + 'gender', + 'value', + 'year', + 'years_ago', + 'date_informal', + ], + filter: [ + { + meta: { index: '89655130-5013-11e9-bce7-4dabcb8bef24', params: {} }, + range: { + date: { + gte: '1960-01-01T10:00:00Z', + lte: '1999-01-01T10:00:00Z', + format: 'strict_date_optional_time', + }, + }, + }, + ], + }, + }) + )) as supertest.Response; + + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/hugedata'); + }); + }); + }); +} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 2981ff81d66eb..b4e05e37d3fda 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -12,7 +12,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Reporting APIs', function () { this.tags('ciGroup2'); loadTestFile(require.resolve('./csv_job_params')); - loadTestFile(require.resolve('./csv_saved_search')); + loadTestFile(require.resolve('./csv_searchsource_immediate')); loadTestFile(require.resolve('./network_policy')); loadTestFile(require.resolve('./spaces')); loadTestFile(require.resolve('./usage')); diff --git a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis.ts b/x-pack/test/reporting_api_integration/reporting_without_security/job_apis.ts index 99832e3f4b1c2..b8ef01f316381 100644 --- a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis.ts +++ b/x-pack/test/reporting_api_integration/reporting_without_security/job_apis.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { forOwn } from 'lodash'; -import { JOB_PARAMS_RISON } from '../fixtures'; +import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../fixtures'; import { FtrProviderContext } from '../ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -35,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) { const { status: resStatus, text: resText } = await supertestNoAuth .post(`/api/reporting/generate/csv`) .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON }); + .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); expect(resStatus).to.be(200); @@ -67,7 +67,7 @@ export default function ({ getService }: FtrProviderContext) { const { status: resStatus, text: resText } = await supertestNoAuth .post(`/api/reporting/generate/csv`) .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON }); + .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); expect(resStatus).to.be(200); @@ -97,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) { const { status: resStatus, text: resText } = await supertestNoAuth .post(`/api/reporting/generate/csv`) .set('kbn-xsrf', 'xxx') - .send({ jobParams: JOB_PARAMS_RISON }); + .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED }); expect(resStatus).to.be(200); From c19ee2ade15dbc166f54ab1911c9b86d36142c34 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 3 Mar 2021 13:36:36 -0700 Subject: [PATCH 02/51] replace PIT solution with scan-and-scroll --- ...gins-data-public.searchsourcefields.pit.md | 14 -- .../search_source/fetch/get_search_params.ts | 3 +- .../data/common/search/search_source/mocks.ts | 1 + .../search/search_source/search_source.ts | 8 +- .../data/common/search/search_source/types.ts | 6 +- src/plugins/data/server/index.ts | 1 + x-pack/plugins/reporting/server/core.ts | 4 +- .../csv_searchsource/execute_job.ts | 9 +- .../generate_csv/generate_csv.test.ts | 15 ++ .../generate_csv/generate_csv.ts | 151 +++++++----------- .../csv_searchsource_immediate/execute_job.ts | 6 +- .../create_mock_reportingplugin.ts | 2 +- 12 files changed, 99 insertions(+), 121 deletions(-) delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md deleted file mode 100644 index c7e426d3f47ca..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.pit.md +++ /dev/null @@ -1,14 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchSourceFields](./kibana-plugin-plugins-data-public.searchsourcefields.md) > [pit](./kibana-plugin-plugins-data-public.searchsourcefields.pit.md) - -## SearchSourceFields.pit property - -Signature: - -```typescript -pit?: { - id: string; - keep_alive?: string; - }; -``` diff --git a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts index 28ee7993c175c..4d62e5771fda5 100644 --- a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts +++ b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts @@ -37,11 +37,12 @@ export function getSearchParamsFromRequest( const { getConfig } = dependencies; const searchParams = getSearchParams(getConfig); // eslint-disable-next-line @typescript-eslint/naming-convention - const { track_total_hits, ...body } = searchRequest.body; + const { scroll, track_total_hits, ...body } = searchRequest.body; return { index: searchRequest.index.title || searchRequest.index, body, + scroll, track_total_hits, ...searchParams, }; diff --git a/src/plugins/data/common/search/search_source/mocks.ts b/src/plugins/data/common/search/search_source/mocks.ts index ade22c20596d9..7eb0d87c0b15c 100644 --- a/src/plugins/data/common/search/search_source/mocks.ts +++ b/src/plugins/data/common/search/search_source/mocks.ts @@ -18,6 +18,7 @@ export const searchSourceInstanceMock: MockedKeys = { setFields: jest.fn().mockReturnThis(), setField: jest.fn().mockReturnThis(), removeField: jest.fn().mockReturnThis(), + flatten: jest.fn().mockImplementation(() => ({ body: {}, index: {} })), getId: jest.fn(), getFields: jest.fn(), getField: jest.fn(), diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 4f0b88f840d60..8d1652635c792 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -439,8 +439,10 @@ export class SearchSource { getConfig(UI_SETTINGS.SORT_OPTIONS) ); return addToBody(key, sort); - case 'pit': - return addToRoot(key, val); + case 'scroll': + return addToBody(key, val); // TODO: should be addParam (same as trackTotalHits) + case 'scrollId': + return addToBody('scroll_id', val); default: return addToBody(key, val); } @@ -540,7 +542,7 @@ export class SearchSource { return field; } - private flatten() { + public flatten() { const { getConfig } = this.dependencies; const searchRequest = this.mergeProps(); searchRequest.body = searchRequest.body || {}; diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index 0fbbaec5c4a6a..2b423ab01d62e 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -100,10 +100,8 @@ export interface SearchSourceFields { searchAfter?: EsQuerySearchAfter; timeout?: string; terminate_after?: number; - pit?: { - id: string; - keep_alive?: string; - }; + scroll?: string; + scrollId?: string[]; parent?: SearchSourceFields; } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 2a21b9e434596..cbf09ef57d96a 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -220,6 +220,7 @@ export { } from '../common'; export { + IScopedSearchClient, ISearchStrategy, ISearchSetup, ISearchStart, diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index 9161a6b551bcd..b79aecdfe174d 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -244,9 +244,9 @@ export class ReportingCore { return await this.getUiSettingsServiceFactory(savedObjectsClient); } - public async getSearchService() { + public async getDataService() { const startDeps = await this.getPluginStartDeps(); - return startDeps.data.search; + return startDeps.data; } public async getEsClient() { diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts index 0453af4ef23e3..b79c1aef6c648 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts @@ -6,11 +6,11 @@ */ import { CSV_JOB_TYPE } from '../../../common/constants'; +import { getFieldFormats } from '../../services'; import { RunTaskFn, RunTaskFnFactory } from '../../types'; import { decryptJobHeaders } from '../common'; import { CsvGenerator } from './generate_csv/generate_csv'; import { TaskPayloadCSV } from './types'; -import { getFieldFormats } from '../../services'; export const runTaskFnFactory: RunTaskFnFactory> = ( reporting, @@ -26,8 +26,10 @@ export const runTaskFnFactory: RunTaskFnFactory> = ( const fakeRequest = reporting.getFakeRequest({ headers }, job.spaceId, logger); const uiSettingsClient = await reporting.getUiSettingsClient(fakeRequest, logger); - const searchService = await reporting.getSearchService(); - const searchSourceService = await searchService.searchSource.asScoped(fakeRequest); + const dataPluginStart = await reporting.getDataService(); + const searchSourceService = await dataPluginStart.search.searchSource.asScoped(fakeRequest); + const data = dataPluginStart.search.asScoped(fakeRequest); + const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( uiSettingsClient ); @@ -38,6 +40,7 @@ export const runTaskFnFactory: RunTaskFnFactory> = ( job, config, esClient, + data, uiSettingsClient, searchSourceService, fieldFormatsRegistry, diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts index 430f8cadbe90d..84c3ca2f8621b 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts @@ -18,6 +18,8 @@ import { ISearchStartSearchSource, } from 'src/plugins/data/common'; import { searchSourceInstanceMock } from 'src/plugins/data/common/search/search_source/mocks'; +import { IScopedSearchClient } from 'src/plugins/data/server'; +import { dataPluginMock } from 'src/plugins/data/server/mocks'; import { ReportingConfig } from '../../../'; import { CancellationToken } from '../../../../common'; import { @@ -38,6 +40,7 @@ const createMockJob = (baseObj: any = {}): JobParamsCSV => ({ }); let mockEsClient: IScopedClusterClient; +let mockDataClient: IScopedSearchClient; let mockConfig: ReportingConfig; let uiSettingsClient: IUiSettingsClient; @@ -75,6 +78,7 @@ const mockFieldFormatsRegistry = ({ beforeEach(async () => { mockEsClient = elasticsearchServiceMock.createScopedClusterClient(); + mockDataClient = dataPluginMock.createStartContract().search.asScoped({} as any); uiSettingsClient = uiSettingsServiceMock .createStartContract() @@ -112,6 +116,7 @@ it('formats an empty search result to CSV content', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -147,6 +152,7 @@ it('formats a search result to CSV content', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -188,6 +194,7 @@ it('calculates the bytes of the content', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -233,6 +240,7 @@ it('warns if max size was reached', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -272,6 +280,7 @@ it('warns if it detects paging through unsorted search results', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -301,6 +310,7 @@ it('warns if it detects paging through poorly sorted data', async () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -340,6 +350,7 @@ describe('fields', () => { createMockJob({ searchSource: {} }), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -393,6 +404,7 @@ describe('fields', () => { }), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -436,6 +448,7 @@ describe('formulas', () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -482,6 +495,7 @@ describe('formulas', () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, @@ -531,6 +545,7 @@ describe('formulas', () => { createMockJob({}), mockConfig, mockEsClient, + mockDataClient, uiSettingsClient, mockSearchSourceService, mockFieldFormatsRegistry, diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 9c0486a40fee9..117fbfc7d9d7e 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -8,13 +8,15 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; +import { IScopedSearchClient } from 'src/plugins/data/server'; import { Datatable } from 'src/plugins/expressions/server'; import { ReportingConfig } from '../../..'; import { - EsQuerySearchAfter, + ES_SEARCH_STRATEGY, FieldFormat, FieldFormatConfig, IFieldFormatsRegistry, + ISearchSource, ISearchStartSearchSource, SearchFieldValue, tabifyDocs, @@ -34,13 +36,13 @@ export class CsvGenerator { private _formatters: Record | null = null; private csvContainsFormulas = false; private maxSizeReached = false; - private needsSorting = false; private csvRowCount = 0; constructor( private job: JobParamsCSV, private config: ReportingConfig, private esClient: IScopedClusterClient, + private data: IScopedSearchClient, private uiSettingsClient: IUiSettingsClient, private searchSourceService: ISearchStartSearchSource, private fieldFormatsRegistry: IFieldFormatsRegistry, @@ -48,6 +50,35 @@ export class CsvGenerator { private logger: LevelLogger ) {} + private async search(searchSource: ISearchSource, scrollSettings: CsvExportSettings['scroll']) { + const { body: searchBody, index: searchIndex } = searchSource.flatten(); + this.logger.debug(`executing search request`); + const searchParams = { + params: { + body: searchBody, + index: searchIndex.title, + scroll: scrollSettings.duration, + size: scrollSettings.size, + }, + }; + const results = ( + await this.data.search(searchParams, { strategy: ES_SEARCH_STRATEGY }).toPromise() + ).rawResponse; + + return results; + } + + private async scroll(scrollId: string, scrollSettings: CsvExportSettings['scroll']) { + this.logger.debug(`executing scroll request`); + const results = ( + await this.esClient.asCurrentUser.scroll({ + scroll: scrollSettings.duration, + scroll_id: scrollId, + }) + ).body as SearchResponse; + return results; + } + /* * Build a map for ordering the fields of search results into CSV columns */ @@ -200,9 +231,6 @@ export class CsvGenerator { } } - /* - * Open a Point In Time on the Elasticsearch index and collect all the data from the index - */ public async generateData(): Promise { const [settings, searchSource] = await Promise.all([ getExportSettings(this.uiSettingsClient, this.config, this.job.browserTimezone, this.logger), @@ -212,34 +240,16 @@ export class CsvGenerator { const index = searchSource.getField('index'); const fields = searchSource.getField('fields'); - const { maxSizeBytes, bom, escapeFormulaValues } = settings; - searchSource.setField('size', settings.scroll.size); + const { maxSizeBytes, bom, escapeFormulaValues, scroll: scrollSettings } = settings; const builder = new MaxSizeStringBuilder(byteSizeValueToNumber(maxSizeBytes), bom); - + const warnings: string[] = []; + let first = true; let currentRecord = -1; let totalRecords = 0; - let first = true; - let lastSortId: EsQuerySearchAfter | undefined; - let pitId: string | undefined; - const warnings: string[] = []; + let scrollId: string | undefined; - // open PIT and set field format config if (index) { - // use _pit API - const { title: indexPatternTitle } = index; - const { duration } = settings.scroll; - this.logger.debug(`Open PIT: index: '${indexPatternTitle}' keep_alive: '${duration}'`); - const { body, statusCode } = await this.esClient.asCurrentUser.openPointInTime({ - index: indexPatternTitle, - keep_alive: duration, - }); - if (statusCode === 404) { - this.logger.error('Unable to open point in time!'); - this.logger.error(new Error(JSON.stringify(body))); - } - pitId = body.id as string; - // apply timezone from the job to all date field formatters try { index.fields.getByType('date').forEach(({ name }) => { @@ -259,40 +269,33 @@ export class CsvGenerator { } } - this.logger.debug(`Received PIT ID: ${pitId?.substring(0, 9)}`); - if (pitId) { - searchSource.setField('pit', { id: pitId, keep_alive: '2m' }); - } else { - this.logger.error(`Unable to open a point in time with ${searchSource.getId()}!`); - } - do { if (this.cancellationToken.isCancelled()) { break; } - - if (lastSortId) { - searchSource.setField('searchAfter', lastSortId); - } let results: SearchResponse | undefined; try { - results = await searchSource.fetch(); + if (scrollId == null) { + // open a scroll cursor in Elasticsearch + results = await this.search(searchSource, scrollSettings); + scrollId = results._scroll_id; + if (results.hits?.total != null) { + totalRecords = results.hits.total; + this.logger.debug(`Total search results: ${totalRecords}`); + } + } else { + // use the scroll cursor in Elasticsearch + results = await this.scroll(scrollId, scrollSettings); + } } catch (err) { this.logger.error(err); } if (!results) { + this.logger.warning(`Search results are undefined!`); break; } - if (results.hits?.total == null) { - this.logger.error('Expected total number of records in the search response'); - totalRecords = -1; - } else { - totalRecords = results.hits.total; - } - this.logger.debug(`Search results: ${totalRecords}`); - let table: Datatable | undefined; try { table = tabifyDocs(results, index, { shallow: true, meta: true }); @@ -318,31 +321,6 @@ export class CsvGenerator { const formatters = this.getFormatters(table); this.generateRows(fields, table, builder, formatters, settings); - const hits = results.hits?.hits || []; - - let tempSortId: EsQuerySearchAfter | undefined; - try { - tempSortId = hits[hits.length - 1]?.sort as EsQuerySearchAfter; - if (lastSortId && tempSortId?.join() === lastSortId?.join()) { - // repeated sort ID: results are not thoroughly sorted - this.needsSorting = true; - } - - const uniqueSortIds = new Set(); - hits.forEach((hit) => { - uniqueSortIds.add(hit.sort?.join()); - }); - if (lastSortId && (!uniqueSortIds.size || uniqueSortIds.size < hits.length)) { - // not enough unique sort IDs for the number of hits: results are not thoroughly sorted - this.needsSorting = true; - } - } catch (err) { - this.logger.error(err); - } - - // update last sort ID for next query - lastSortId = tempSortId; - // update iterator currentRecord += table.rows.length; } while (currentRecord < totalRecords - 1); @@ -352,12 +330,6 @@ export class CsvGenerator { `Finished generating. Total size in bytes: ${size}. Row count: ${this.csvRowCount}.` ); - // the row count is wrong and it's not because of max size limit - // results are not thoroughly sorted - if (this.csvRowCount !== totalRecords && !this.maxSizeReached) { - this.needsSorting = true; - } - // Add warnings to be logged if (this.csvContainsFormulas && escapeFormulaValues) { warnings.push( @@ -367,18 +339,16 @@ export class CsvGenerator { ); } - if (this.needsSorting) { - warnings.push( - i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.unsortedResults', { - defaultMessage: `The export may have duplicated or missing data: sort values in the search results must be unique`, - }) - ); - } - - // clean PIT - if (pitId) { - this.logger.debug(`Closing PIT`); - await this.esClient.asCurrentUser.closePointInTime({ body: { id: pitId } }); + // clear scrollID + if (scrollId) { + this.logger.debug(`executing clearScroll request`); + try { + await this.esClient.asCurrentUser.clearScroll({ scroll_id: [scrollId] }); + } catch (err) { + this.logger.error(err); + } + } else { + this.logger.warn(`No scrollId to clear!`); } return { @@ -386,7 +356,6 @@ export class CsvGenerator { content_type: CONTENT_TYPE_CSV, csv_contains_formulas: this.csvContainsFormulas && !escapeFormulaValues, max_size_reached: this.maxSizeReached, - needs_sorting: this.needsSorting, size, warnings, }; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts index eab8a06b10121..b6fe123c411db 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts @@ -36,8 +36,9 @@ export const runTaskFnFactory: RunTaskFnFactory = function e const esClient = (await reporting.getEsClient()).asScoped(req); const savedObjectsClient = context.core.savedObjects.client; const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); - const searchService = await reporting.getSearchService(); - const searchSourceService = await searchService.searchSource.asScoped(req); + const dataPluginStart = await reporting.getDataService(); + const searchSourceService = await dataPluginStart.search.searchSource.asScoped(req); + const data = dataPluginStart.search.asScoped(req); const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( uiSettingsClient @@ -52,6 +53,7 @@ export const runTaskFnFactory: RunTaskFnFactory = function e job, config, esClient, + data, uiSettingsClient, searchSourceService, fieldFormatsRegistry, diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 5341db12f6548..b4bda5e041764 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -135,7 +135,7 @@ export const createMockReportingCore = async ( const mockReportingCore = ({ getConfig: () => config, getElasticsearchService: () => setupDepsMock?.elasticsearch, - getSearchService: () => startDepsMock?.data?.search, + getDataService: () => startDepsMock?.data, } as unknown) as ReportingCore; if (!setupDepsMock) { From 3c519c1850b6e87fb753f45dce24cbb0faa62832 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 4 Mar 2021 17:54:13 -0700 Subject: [PATCH 03/51] update tests --- .../csv_searchsource/execute_job.ts | 25 +- .../__snapshots__/generate_csv.test.ts.snap | 157 +++++ .../generate_csv/generate_csv.test.ts | 545 +++++++++--------- .../generate_csv/generate_csv.ts | 37 +- .../csv_searchsource_immediate/execute_job.ts | 32 +- 5 files changed, 485 insertions(+), 311 deletions(-) create mode 100644 x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts index b79c1aef6c648..07c68f22c2f4f 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts @@ -25,29 +25,22 @@ export const runTaskFnFactory: RunTaskFnFactory> = ( const headers = await decryptJobHeaders(encryptionKey, job.headers, logger); const fakeRequest = reporting.getFakeRequest({ headers }, job.spaceId, logger); const uiSettingsClient = await reporting.getUiSettingsClient(fakeRequest, logger); - const dataPluginStart = await reporting.getDataService(); - const searchSourceService = await dataPluginStart.search.searchSource.asScoped(fakeRequest); - const data = dataPluginStart.search.asScoped(fakeRequest); - const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( uiSettingsClient ); - const esClient = (await reporting.getEsClient()).asScoped(fakeRequest); - - const csv = new CsvGenerator( - job, - config, - esClient, - data, - uiSettingsClient, - searchSourceService, + const clients = { + uiSettings: uiSettingsClient, + data: dataPluginStart.search.asScoped(fakeRequest), + es: (await reporting.getEsClient()).asScoped(fakeRequest), + }; + const dependencies = { + searchSourceStart: await dataPluginStart.search.searchSource.asScoped(fakeRequest), fieldFormatsRegistry, - cancellationToken, - logger - ); + }; + const csv = new CsvGenerator(job, config, clients, dependencies, cancellationToken, logger); return await csv.generateData(); }; }; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap new file mode 100644 index 0000000000000..6ec54a1c9c112 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap @@ -0,0 +1,157 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`fields cells can be multi-value 1`] = ` +"\\"_id\\",sku +\\"my-cool-id\\",\\"This is a cool SKU., This is also a cool SKU.\\" +" +`; + +exports[`fields provides top-level underscored fields as columns 1`] = ` +"\\"_id\\",\\"_index\\",date,message +\\"my-cool-id\\",\\"my-cool-index\\",\\"2020-12-31T00:14:28.000Z\\",\\"it's nice to see you\\" +" +`; + +exports[`formats a search result to CSV content 1`] = ` +"date,ip,message +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is a great message!\\" +" +`; + +exports[`formats an empty search result to CSV content 1`] = ` +"date,ip,message +" +`; + +exports[`formulas can check for formulas, without escaping them 1`] = ` +"date,ip,message +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"=SUM(A1:A2)\\" +" +`; + +exports[`formulas escapes formula values in a cell, doesn't warn the csv contains formulas 1`] = ` +"date,ip,message +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"'=SUM(A1:A2)\\" +" +`; + +exports[`formulas escapes formula values in a header, doesn't warn the csv contains formulas 1`] = ` +"date,ip,\\"'=SUM(A1:A2)\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is great data\\" +" +`; + +exports[`uses the scrollId to page all the data 1`] = ` +"date,ip,message +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from the initial search\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"hit from a subsequent scroll\\" +" +`; + +exports[`warns if max size was reached 1`] = ` +"date,ip,message +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" +\\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" +" +`; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts index 84c3ca2f8621b..0e651c98ce06b 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts @@ -5,18 +5,15 @@ * 2.0. */ +import * as Rx from 'rxjs'; import { identity, range } from 'lodash'; -import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; +import { IScopedClusterClient, IUiSettingsClient, SearchResponse } from 'src/core/server'; import { elasticsearchServiceMock, savedObjectsClientMock, uiSettingsServiceMock, } from 'src/core/server/mocks'; -import { - EsQuerySearchAfter, - FieldFormatsRegistry, - ISearchStartSearchSource, -} from 'src/plugins/data/common'; +import { FieldFormatsRegistry, ISearchStartSearchSource } from 'src/plugins/data/common'; import { searchSourceInstanceMock } from 'src/plugins/data/common/search/search_source/mocks'; import { IScopedSearchClient } from 'src/plugins/data/server'; import { dataPluginMock } from 'src/plugins/data/server/mocks'; @@ -49,12 +46,21 @@ const mockSearchSourceService: jest.Mocked = { create: jest.fn().mockReturnValue(searchSourceMock), createEmpty: jest.fn().mockReturnValue(searchSourceMock), }; -const mockSearchSourceFetchDefault = jest.fn().mockResolvedValue({ - hits: { - hits: [], - total: 0, - }, -}); +const mockDataClientSearchDefault = jest.fn().mockImplementation( + (): Rx.Observable<{ rawResponse: SearchResponse }> => + Rx.of({ + rawResponse: { + took: 1, + timed_out: false, + _shards: { total: 1, successful: 1, failed: 0, skipped: 0 }, + hits: { + hits: [], + total: 0, + max_score: 0, + }, + }, + }) +); const mockSearchSourceGetFieldDefault = jest.fn().mockImplementation((key: string) => { switch (key) { case 'fields': @@ -79,6 +85,7 @@ const mockFieldFormatsRegistry = ({ beforeEach(async () => { mockEsClient = elasticsearchServiceMock.createScopedClusterClient(); mockDataClient = dataPluginMock.createStartContract().search.asScoped({} as any); + mockDataClient.search = mockDataClientSearchDefault; uiSettingsClient = uiSettingsServiceMock .createStartContract() @@ -106,7 +113,6 @@ beforeEach(async () => { ); searchSourceMock.getField = mockSearchSourceGetFieldDefault; - searchSourceMock.fetch = mockSearchSourceFetchDefault; }); const logger = createMockLevelLogger(); @@ -115,61 +121,63 @@ it('formats an empty search result to CSV content', async () => { const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,message - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); - expect(csvResult.needs_sorting).toBe(false); }); it('formats a search result to CSV content', async () => { - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - fields: { - date: `["2020-12-31T00:14:28.000Z"]`, - ip: `["110.135.176.89"]`, - message: `["This is a great message!"]`, - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + fields: { + date: `["2020-12-31T00:14:28.000Z"]`, + ip: `["110.135.176.89"]`, + message: `["This is a great message!"]`, + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,message - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is a great message!\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); - expect(csvResult.needs_sorting).toBe(false); }); -const TEST_NUM_TOTAL = 100; +const HITS_TOTAL = 100; it('calculates the bytes of the content', async () => { searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { @@ -178,33 +186,39 @@ it('calculates the bytes of the content', async () => { } return mockSearchSourceGetFieldDefault(key); }); - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: range(0, TEST_NUM_TOTAL).map((hit, i) => ({ - fields: { - message: ['this is a great message'], + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: range(0, HITS_TOTAL).map((hit, i) => ({ + fields: { + message: ['this is a great message'], + }, + })), + total: HITS_TOTAL, }, - sort: [i, 1] as EsQuerySearchAfter, - })), - total: TEST_NUM_TOTAL, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); expect(csvResult.size).toBe(2608); expect(csvResult.max_size_reached).toBe(false); - expect(csvResult.needs_sorting).toBe(false); expect(csvResult.warnings).toEqual([]); }); @@ -222,103 +236,94 @@ it('warns if max size was reached', async () => { }) ); - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: range(0, TEST_NUM_TOTAL).map((hit, i) => ({ - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - message: ['super cali fragile istic XPLA docious'], + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: range(0, HITS_TOTAL).map((hit, i) => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['super cali fragile istic XPLA docious'], + }, + })), + total: HITS_TOTAL, }, - sort: [i, ''] as EsQuerySearchAfter, - })), - total: TEST_NUM_TOTAL, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); expect(csvResult.max_size_reached).toBe(true); - expect(csvResult.needs_sorting).toBe(false); expect(csvResult.warnings).toEqual([]); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,message - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"super cali fragile istic XPLA docious\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); }); -it('warns if it detects paging through unsorted search results', async () => { - searchSourceMock.fetch = jest.fn().mockResolvedValue({ - hits: { - hits: range(0, 15).map(() => ({ - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - message: ['super cali fragile istic XPLA docious'], +it('uses the scrollId to page all the data', async () => { + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + _scroll_id: 'awesome-scroll-hero', + hits: { + hits: range(0, HITS_TOTAL / 10).map((hit, i) => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['hit from the initial search'], + }, + })), + total: HITS_TOTAL, }, - })), - total: 50, - }, - }); - - const generateCsv = new CsvGenerator( - createMockJob({}), - mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, - new CancellationToken(), - logger + }, + }) ); - const csvResult = await generateCsv.generateData(); - expect(csvResult.needs_sorting).toBe(true); -}); - -it('warns if it detects paging through poorly sorted data', async () => { - searchSourceMock.fetch = jest.fn().mockResolvedValue({ - hits: { - hits: range(0, 15).map(() => ({ - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - message: ['super cali fragile istic XPLA docious'], - sort: [0, 0] as EsQuerySearchAfter, - }, - })), - total: 50, + mockEsClient.asCurrentUser.scroll = jest.fn().mockResolvedValue({ + body: { + hits: { + hits: range(0, HITS_TOTAL / 10).map((hit, i) => ({ + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: ['hit from a subsequent scroll'], + }, + })), + }, }, }); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.needs_sorting).toBe(true); + expect(csvResult.warnings).toEqual([]); + expect(csvResult.content).toMatchSnapshot(); }); describe('fields', () => { @@ -329,42 +334,44 @@ describe('fields', () => { } return mockSearchSourceGetFieldDefault(key); }); - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - _id: 'my-cool-id', - _index: 'my-cool-index', - _version: 4, - fields: { - sku: [`This is a cool SKU.`, `This is also a cool SKU.`], - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + _id: 'my-cool-id', + _index: 'my-cool-index', + _version: 4, + fields: { + sku: [`This is a cool SKU.`, `This is also a cool SKU.`], + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({ searchSource: {} }), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "\\"_id\\",sku - \\"my-cool-id\\",\\"This is a cool SKU., This is also a cool SKU.\\" - " - `); - expect(csvResult.needs_sorting).toBe(false); + expect(csvResult.content).toMatchSnapshot(); }); it('provides top-level underscored fields as columns', async () => { @@ -374,23 +381,26 @@ describe('fields', () => { } return mockSearchSourceGetFieldDefault(key); }); - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - _id: 'my-cool-id', - _index: 'my-cool-index', - _version: 4, - fields: { - date: ['2020-12-31T00:14:28.000Z'], - message: [`it's nice to see you`], - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + _id: 'my-cool-id', + _index: 'my-cool-index', + _version: 4, + fields: { + date: ['2020-12-31T00:14:28.000Z'], + message: [`it's nice to see you`], + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({ @@ -403,24 +413,23 @@ describe('fields', () => { }, }), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "\\"_id\\",\\"_index\\",date,message - \\"my-cool-id\\",\\"my-cool-index\\",\\"2020-12-31T00:14:28.000Z\\",\\"it's nice to see you\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); - expect(csvResult.needs_sorting).toBe(false); }); }); @@ -428,61 +437,66 @@ describe('formulas', () => { const TEST_FORMULA = '=SUM(A1:A2)'; it(`escapes formula values in a cell, doesn't warn the csv contains formulas`, async () => { - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - message: [TEST_FORMULA], - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: [TEST_FORMULA], + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,message - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"'=SUM(A1:A2)\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); - expect(csvResult.needs_sorting).toBe(false); }); it(`escapes formula values in a header, doesn't warn the csv contains formulas`, async () => { - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - [TEST_FORMULA]: 'This is great data', - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + [TEST_FORMULA]: 'This is great data', + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { if (key === 'fields') { @@ -494,24 +508,23 @@ describe('formulas', () => { const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,\\"'=SUM(A1:A2)\\" - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is great data\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); - expect(csvResult.needs_sorting).toBe(false); }); it('can check for formulas, without escaping them', async () => { @@ -525,42 +538,44 @@ describe('formulas', () => { }, }) ); - searchSourceMock.fetch = jest.fn().mockResolvedValueOnce({ - hits: { - hits: [ - { - fields: { - date: ['2020-12-31T00:14:28.000Z'], - ip: ['110.135.176.89'], - message: [TEST_FORMULA], - }, - sort: [1, 'a'] as EsQuerySearchAfter, + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + fields: { + date: ['2020-12-31T00:14:28.000Z'], + ip: ['110.135.176.89'], + message: [TEST_FORMULA], + }, + }, + ], + total: 1, }, - ], - total: 1, - }, - }); + }, + }) + ); const generateCsv = new CsvGenerator( createMockJob({}), mockConfig, - mockEsClient, - mockDataClient, - uiSettingsClient, - mockSearchSourceService, - mockFieldFormatsRegistry, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, new CancellationToken(), logger ); const csvResult = await generateCsv.generateData(); - expect(csvResult.content).toMatchInlineSnapshot(` - "date,ip,message - \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"=SUM(A1:A2)\\" - " - `); + expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(true); - expect(csvResult.needs_sorting).toBe(false); }); }); diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 117fbfc7d9d7e..baeb74748917a 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -31,6 +31,17 @@ import { cellHasFormulas } from './cell_has_formula'; import { CsvExportSettings, getExportSettings } from './get_export_settings'; import { MaxSizeStringBuilder } from './max_size_string_builder'; +interface Clients { + es: IScopedClusterClient; + data: IScopedSearchClient; + uiSettings: IUiSettingsClient; +} + +interface Dependencies { + searchSourceStart: ISearchStartSearchSource; + fieldFormatsRegistry: IFieldFormatsRegistry; +} + export class CsvGenerator { private _columnMap: number[] | null = null; private _formatters: Record | null = null; @@ -41,11 +52,8 @@ export class CsvGenerator { constructor( private job: JobParamsCSV, private config: ReportingConfig, - private esClient: IScopedClusterClient, - private data: IScopedSearchClient, - private uiSettingsClient: IUiSettingsClient, - private searchSourceService: ISearchStartSearchSource, - private fieldFormatsRegistry: IFieldFormatsRegistry, + private clients: Clients, + private dependencies: Dependencies, private cancellationToken: CancellationToken, private logger: LevelLogger ) {} @@ -62,7 +70,7 @@ export class CsvGenerator { }, }; const results = ( - await this.data.search(searchParams, { strategy: ES_SEARCH_STRATEGY }).toPromise() + await this.clients.data.search(searchParams, { strategy: ES_SEARCH_STRATEGY }).toPromise() ).rawResponse; return results; @@ -71,7 +79,7 @@ export class CsvGenerator { private async scroll(scrollId: string, scrollSettings: CsvExportSettings['scroll']) { this.logger.debug(`executing scroll request`); const results = ( - await this.esClient.asCurrentUser.scroll({ + await this.clients.es.asCurrentUser.scroll({ scroll: scrollSettings.duration, scroll_id: scrollId, }) @@ -113,7 +121,7 @@ export class CsvGenerator { // initialize field formats const formatters: Record = {}; table.columns.forEach((c) => { - const fieldFormat = this.fieldFormatsRegistry.deserialize(c.meta.params); + const fieldFormat = this.dependencies.fieldFormatsRegistry.deserialize(c.meta.params); formatters[c.id] = fieldFormat; }); @@ -233,8 +241,13 @@ export class CsvGenerator { public async generateData(): Promise { const [settings, searchSource] = await Promise.all([ - getExportSettings(this.uiSettingsClient, this.config, this.job.browserTimezone, this.logger), - this.searchSourceService.create(this.job.searchSource), + getExportSettings( + this.clients.uiSettings, + this.config, + this.job.browserTimezone, + this.logger + ), + this.dependencies.searchSourceStart.create(this.job.searchSource), ]); const index = searchSource.getField('index'); @@ -278,7 +291,7 @@ export class CsvGenerator { if (scrollId == null) { // open a scroll cursor in Elasticsearch results = await this.search(searchSource, scrollSettings); - scrollId = results._scroll_id; + scrollId = results?._scroll_id; if (results.hits?.total != null) { totalRecords = results.hits.total; this.logger.debug(`Total search results: ${totalRecords}`); @@ -343,7 +356,7 @@ export class CsvGenerator { if (scrollId) { this.logger.debug(`executing clearScroll request`); try { - await this.esClient.asCurrentUser.clearScroll({ scroll_id: [scrollId] }); + await this.clients.es.asCurrentUser.clearScroll({ scroll_id: [scrollId] }); } catch (err) { this.logger.error(err); } diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts index b6fe123c411db..0a6f806b4e8b2 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts @@ -33,34 +33,30 @@ export const runTaskFnFactory: RunTaskFnFactory = function e const logger = parentLogger.clone([CSV_SEARCHSOURCE_IMMEDIATE_TYPE, 'execute-job']); return async function runTask(jobId, immediateJobParams, context, req) { - const esClient = (await reporting.getEsClient()).asScoped(req); + const job = { + objectType: 'immediate-search', + ...immediateJobParams, + }; + const savedObjectsClient = context.core.savedObjects.client; const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); const dataPluginStart = await reporting.getDataService(); - const searchSourceService = await dataPluginStart.search.searchSource.asScoped(req); - const data = dataPluginStart.search.asScoped(req); - const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( uiSettingsClient ); - const job = { - objectType: 'immediate-search', - ...immediateJobParams, + const clients = { + uiSettings: uiSettingsClient, + data: dataPluginStart.search.asScoped(req), + es: (await reporting.getEsClient()).asScoped(req), }; - - const csv = new CsvGenerator( - job, - config, - esClient, - data, - uiSettingsClient, - searchSourceService, + const dependencies = { fieldFormatsRegistry, - new CancellationToken(), - logger - ); + searchSourceStart: await dataPluginStart.search.searchSource.asScoped(req), + }; + const cancellationToken = new CancellationToken(); + const csv = new CsvGenerator(job, config, clients, dependencies, cancellationToken, logger); const result = await csv.generateData(); if (result.csv_contains_formulas) { From 49c4448dafc660e9700ef3b1a21b943163e6c801 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 4 Mar 2021 21:19:45 -0700 Subject: [PATCH 04/51] cleanup --- .../kibana-plugin-plugins-data-public.searchsourcefields.md | 1 - .../common/search/search_source/fetch/get_search_params.ts | 3 +-- .../data/common/search/search_source/search_source.ts | 4 ---- src/plugins/data/common/search/search_source/types.ts | 3 +-- src/plugins/data/public/public.api.md | 5 ----- x-pack/plugins/reporting/server/core.ts | 1 + 6 files changed, 3 insertions(+), 14 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md index bd85d67772cd9..d0f53936eb56a 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md @@ -25,7 +25,6 @@ export interface SearchSourceFields | [highlightAll](./kibana-plugin-plugins-data-public.searchsourcefields.highlightall.md) | boolean | | | [index](./kibana-plugin-plugins-data-public.searchsourcefields.index.md) | IndexPattern | | | [parent](./kibana-plugin-plugins-data-public.searchsourcefields.parent.md) | SearchSourceFields | | -| [pit](./kibana-plugin-plugins-data-public.searchsourcefields.pit.md) | {
id: string;
keep_alive?: string;
} | | | [query](./kibana-plugin-plugins-data-public.searchsourcefields.query.md) | Query | [Query](./kibana-plugin-plugins-data-public.query.md) | | [searchAfter](./kibana-plugin-plugins-data-public.searchsourcefields.searchafter.md) | EsQuerySearchAfter | | | [size](./kibana-plugin-plugins-data-public.searchsourcefields.size.md) | number | | diff --git a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts index 4d62e5771fda5..28ee7993c175c 100644 --- a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts +++ b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts @@ -37,12 +37,11 @@ export function getSearchParamsFromRequest( const { getConfig } = dependencies; const searchParams = getSearchParams(getConfig); // eslint-disable-next-line @typescript-eslint/naming-convention - const { scroll, track_total_hits, ...body } = searchRequest.body; + const { track_total_hits, ...body } = searchRequest.body; return { index: searchRequest.index.title || searchRequest.index, body, - scroll, track_total_hits, ...searchParams, }; diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 8d1652635c792..de541732b4b46 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -439,10 +439,6 @@ export class SearchSource { getConfig(UI_SETTINGS.SORT_OPTIONS) ); return addToBody(key, sort); - case 'scroll': - return addToBody(key, val); // TODO: should be addParam (same as trackTotalHits) - case 'scrollId': - return addToBody('scroll_id', val); default: return addToBody(key, val); } diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index 2b423ab01d62e..a178b38693d92 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -100,8 +100,7 @@ export interface SearchSourceFields { searchAfter?: EsQuerySearchAfter; timeout?: string; terminate_after?: number; - scroll?: string; - scrollId?: string[]; + parent?: SearchSourceFields; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 9f6c7e424cdbf..9720395881ea3 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2438,11 +2438,6 @@ export interface SearchSourceFields { // (undocumented) parent?: SearchSourceFields; // (undocumented) - pit?: { - id: string; - keep_alive?: string; - }; - // (undocumented) query?: Query; // Warning: (ae-forgotten-export) The symbol "EsQuerySearchAfter" needs to be exported by the entry point index.d.ts // diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index b79aecdfe174d..59513fcffd35b 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -185,6 +185,7 @@ export class ReportingCore { return this.pluginSetupDeps; } + // NOTE: Uses the Legacy API public getElasticsearchService() { return this.getPluginSetupDeps().elasticsearch; } From ba9e1e6198654e1dd4dc7d0583e8e67d03ac07c4 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 4 Mar 2021 21:24:50 -0700 Subject: [PATCH 05/51] simplify pr --- .../export_types/csv/generate_csv/check_cells_for_formulas.ts | 2 +- x-pack/plugins/reporting/server/plugin.ts | 2 +- .../plugins/reporting/server/routes/lib/get_document_payload.ts | 2 -- .../reporting_api_integration/reporting_and_security.config.ts | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts index c2114bc6bcd1e..f650bbaed1271 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { keys, pick, some, values } from 'lodash'; +import { pick, keys, values, some } from 'lodash'; import { cellHasFormulas } from '../../csv_searchsource/generate_csv/cell_has_formula'; interface IFlattened { diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 6605ec37e57f8..f6fc846250872 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -118,13 +118,13 @@ export class ReportingPlugin const esqueue = await createQueueFactory(reportingCore, store, logger); // starts polling for pending jobs reportingCore.pluginStart({ - data: plugins.data, browserDriverFactory, savedObjects: core.savedObjects, uiSettings: core.uiSettings, esqueue, store, esClient: core.elasticsearch.client, + data: plugins.data, }); this.logger.debug('Start complete'); diff --git a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts index 7ae6159863970..4e8e888e4e266 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts @@ -36,11 +36,9 @@ const getReportingHeaders = (output: TaskRunResult, exportType: ExportTypeDefini if (exportType.jobType === CSV_JOB_TYPE || exportType.jobType === CSV_JOB_TYPE_DEPRECATED) { const csvContainsFormulas = get(output, 'csv_contains_formulas', false); - const csvRowCount = get(output, 'csv_row_count', false); const maxSizedReach = get(output, 'max_size_reached', false); metaDataHeaders['kbn-csv-contains-formulas'] = csvContainsFormulas; - metaDataHeaders['kbn-csv-num-rows'] = csvRowCount; metaDataHeaders['kbn-max-size-reached'] = maxSizedReach; } diff --git a/x-pack/test/reporting_api_integration/reporting_and_security.config.ts b/x-pack/test/reporting_api_integration/reporting_and_security.config.ts index 14e7d9ff67a2b..a1b0e8145391a 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security.config.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security.config.ts @@ -43,7 +43,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--server.port=${kbnTestConfig.getPort()}`, `--xpack.reporting.capture.maxAttempts=1`, `--xpack.reporting.csv.maxSizeBytes=2850`, - `--xpack.reporting.csv.escapeFormulaValues=true`, `--xpack.reporting.queue.pollInterval=3000`, `--xpack.security.session.idleTimeout=3600000`, `--xpack.reporting.capture.networkPolicy.rules=${JSON.stringify(testPolicyRules)}`, From ab9f4d9642136fb0f53213dbe06037efaa89b6b9 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 4 Mar 2021 21:45:31 -0700 Subject: [PATCH 06/51] update docs --- ...plugin-plugins-data-public.searchsource.md | 1 + .../kibana-plugin-plugins-data-server.md | 1 + src/plugins/data/public/public.api.md | 2 + src/plugins/data/server/server.api.md | 55 +++++++++++++------ .../csv_searchsource_immediate.snap | 6 +- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md index b2382d35f7d76..1cee2e888fd40 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md @@ -34,6 +34,7 @@ export declare class SearchSource | [destroy()](./kibana-plugin-plugins-data-public.searchsource.destroy.md) | | Completely destroy the SearchSource. {undefined} | | [fetch(options)](./kibana-plugin-plugins-data-public.searchsource.fetch.md) | | Fetch this source and reject the returned Promise on error | | [fetch$(options)](./kibana-plugin-plugins-data-public.searchsource.fetch_.md) | | Fetch this source from Elasticsearch, returning an observable over the response(s) | +| [flatten()](./kibana-plugin-plugins-data-public.searchsource.flatten.md) | | | | [getField(field, recurse)](./kibana-plugin-plugins-data-public.searchsource.getfield.md) | | Gets a single field from the fields | | [getFields()](./kibana-plugin-plugins-data-public.searchsource.getfields.md) | | returns all search source fields | | [getId()](./kibana-plugin-plugins-data-public.searchsource.getid.md) | | returns search source id | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 491babcdfdecf..235f80f2fbdff 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -52,6 +52,7 @@ | [IFieldSubType](./kibana-plugin-plugins-data-server.ifieldsubtype.md) | | | [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) | | | [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Interface for an index pattern saved object | +| [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) | | | [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | | | [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) | | | [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 9720395881ea3..0f5c275f9c919 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2389,6 +2389,8 @@ export class SearchSource { fetch$(options?: ISearchOptions): import("rxjs").Observable>; // @deprecated fetch(options?: ISearchOptions): Promise>; + // (undocumented) + flatten(): Record; getField(field: K, recurse?: boolean): SearchSourceFields[K]; getFields(): SearchSourceFields; getId(): string; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index ec5ae2f129057..ec0579652dc99 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -951,6 +951,29 @@ export class IndexPatternsServiceProvider implements Plugin_3 { - // Warning: (ae-forgotten-export) The symbol "IScopedSearchSessionsClient" needs to be exported by the entry point index.d.ts - // // (undocumented) asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient; } @@ -998,8 +1019,6 @@ export interface ISearchStart IScopedSearchClient; getSearchStrategy: (name?: string) => ISearchStrategy; @@ -1463,20 +1482,20 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "HistogramFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:128:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:128:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:245:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:246:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:255:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:261:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:269:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:246:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:247:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // src/plugins/data/server/search/types.ts:114:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index ff7ce7f5fedfb..f560a6c55ce9a 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -15,7 +15,7 @@ exports[`Reporting APIs CSV generation from SearchSource date formatting Formatt `; exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, custom timezone (Phoenix) 1`] = ` -"\\"'@timestamp\\",clientip,extension +"\\"@timestamp\\",clientip,extension \\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",jpg \\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",jpg \\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",jpg @@ -75,7 +75,7 @@ exports[`Reporting APIs CSV generation from SearchSource date formatting With fi `; exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, default to UTC 1`] = ` -"\\"'@timestamp\\",clientip,extension +"\\"@timestamp\\",clientip,extension \\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg \\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg \\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg @@ -135,7 +135,7 @@ exports[`Reporting APIs CSV generation from SearchSource date formatting With fi `; exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, explicit UTC format 1`] = ` -"\\"'@timestamp\\",clientip,extension +"\\"@timestamp\\",clientip,extension \\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg \\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg \\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg From 802e6c6502aace0780b9754c3d4333756d5a1ef8 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 4 Mar 2021 21:45:38 -0700 Subject: [PATCH 07/51] update docs --- ...lugins-data-public.searchsource.flatten.md | 15 ++++++++++++ ...erver.iscopedsearchclient.cancelsession.md | 11 +++++++++ ...erver.iscopedsearchclient.deletesession.md | 11 +++++++++ ...erver.iscopedsearchclient.extendsession.md | 11 +++++++++ ...server.iscopedsearchclient.findsessions.md | 11 +++++++++ ...a-server.iscopedsearchclient.getsession.md | 11 +++++++++ ...plugins-data-server.iscopedsearchclient.md | 24 +++++++++++++++++++ ...-server.iscopedsearchclient.savesession.md | 11 +++++++++ ...erver.iscopedsearchclient.updatesession.md | 11 +++++++++ 9 files changed, 116 insertions(+) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md new file mode 100644 index 0000000000000..bf70f7b88f2fd --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) > [flatten](./kibana-plugin-plugins-data-public.searchsource.flatten.md) + +## SearchSource.flatten() method + +Signature: + +```typescript +flatten(): Record; +``` +Returns: + +`Record` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md new file mode 100644 index 0000000000000..3b38e64ecc3da --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [cancelSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md) + +## IScopedSearchClient.cancelSession property + +Signature: + +```typescript +cancelSession: IScopedSearchSessionsClient['cancel']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md new file mode 100644 index 0000000000000..609c730c2911c --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [deleteSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md) + +## IScopedSearchClient.deleteSession property + +Signature: + +```typescript +deleteSession: IScopedSearchSessionsClient['delete']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md new file mode 100644 index 0000000000000..33ce8f2a82d0f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [extendSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md) + +## IScopedSearchClient.extendSession property + +Signature: + +```typescript +extendSession: IScopedSearchSessionsClient['extend']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md new file mode 100644 index 0000000000000..2a78e09841e77 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [findSessions](./kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md) + +## IScopedSearchClient.findSessions property + +Signature: + +```typescript +findSessions: IScopedSearchSessionsClient['find']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md new file mode 100644 index 0000000000000..4afcf4ad29195 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [getSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md) + +## IScopedSearchClient.getSession property + +Signature: + +```typescript +getSession: IScopedSearchSessionsClient['get']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.md new file mode 100644 index 0000000000000..41ac662905b6b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) + +## IScopedSearchClient interface + +Signature: + +```typescript +export interface IScopedSearchClient extends ISearchClient +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [cancelSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.cancelsession.md) | IScopedSearchSessionsClient['cancel'] | | +| [deleteSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.deletesession.md) | IScopedSearchSessionsClient['delete'] | | +| [extendSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.extendsession.md) | IScopedSearchSessionsClient['extend'] | | +| [findSessions](./kibana-plugin-plugins-data-server.iscopedsearchclient.findsessions.md) | IScopedSearchSessionsClient['find'] | | +| [getSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.getsession.md) | IScopedSearchSessionsClient['get'] | | +| [saveSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md) | IScopedSearchSessionsClient['save'] | | +| [updateSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md) | IScopedSearchSessionsClient['update'] | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md new file mode 100644 index 0000000000000..78cd49c376005 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [saveSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.savesession.md) + +## IScopedSearchClient.saveSession property + +Signature: + +```typescript +saveSession: IScopedSearchSessionsClient['save']; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md new file mode 100644 index 0000000000000..5e010f9168e43 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IScopedSearchClient](./kibana-plugin-plugins-data-server.iscopedsearchclient.md) > [updateSession](./kibana-plugin-plugins-data-server.iscopedsearchclient.updatesession.md) + +## IScopedSearchClient.updateSession property + +Signature: + +```typescript +updateSession: IScopedSearchSessionsClient['update']; +``` From 223371792f0538977e896b386367080b6da167b1 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 09:39:18 -0700 Subject: [PATCH 08/51] update telemetry schema --- .../schema/xpack_plugins.json | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 4a0ab555f8f40..8367fcb6deef2 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -2436,6 +2436,16 @@ } } }, + "csv_searchsource": { + "properties": { + "available": { + "type": "boolean" + }, + "total": { + "type": "long" + } + } + }, "PNG": { "properties": { "available": { @@ -2521,6 +2531,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2564,6 +2587,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2607,6 +2643,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2650,6 +2699,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2693,6 +2755,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2736,6 +2811,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2787,6 +2875,16 @@ } } }, + "csv_searchsource": { + "properties": { + "available": { + "type": "boolean" + }, + "total": { + "type": "long" + } + } + }, "PNG": { "properties": { "available": { @@ -2872,6 +2970,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2915,6 +3026,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2958,6 +3082,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3001,6 +3138,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3044,6 +3194,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3087,6 +3250,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { From 6987ab9b37fc427ded67710bd0472404a0bcac09 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 10:06:20 -0700 Subject: [PATCH 09/51] use getSearchRequestBody instead of flatten --- .../search/search_source/search_source.ts | 2 +- .../generate_csv/generate_csv.ts | 52 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index de541732b4b46..f11e7f06b6ab9 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -538,7 +538,7 @@ export class SearchSource { return field; } - public flatten() { + private flatten() { const { getConfig } = this.dependencies; const searchRequest = this.mergeProps(); searchRequest.body = searchRequest.body || {}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index baeb74748917a..7d6a53c90ab4c 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -16,6 +16,7 @@ import { FieldFormat, FieldFormatConfig, IFieldFormatsRegistry, + IndexPattern, ISearchSource, ISearchStartSearchSource, SearchFieldValue, @@ -58,13 +59,17 @@ export class CsvGenerator { private logger: LevelLogger ) {} - private async search(searchSource: ISearchSource, scrollSettings: CsvExportSettings['scroll']) { - const { body: searchBody, index: searchIndex } = searchSource.flatten(); + private async scan( + index: IndexPattern, + searchSource: ISearchSource, + scrollSettings: CsvExportSettings['scroll'] + ) { + const searchBody = await searchSource.getSearchRequestBody(); this.logger.debug(`executing search request`); const searchParams = { params: { body: searchBody, - index: searchIndex.title, + index: index.title, scroll: scrollSettings.duration, size: scrollSettings.size, }, @@ -251,6 +256,11 @@ export class CsvGenerator { ]); const index = searchSource.getField('index'); + + if (!index) { + throw new Error(`The search must have a revference to an index pattern!`); + } + const fields = searchSource.getField('fields'); const { maxSizeBytes, bom, escapeFormulaValues, scroll: scrollSettings } = settings; @@ -262,24 +272,22 @@ export class CsvGenerator { let totalRecords = 0; let scrollId: string | undefined; - if (index) { - // apply timezone from the job to all date field formatters - try { - index.fields.getByType('date').forEach(({ name }) => { - this.logger.debug(`setting timezone on ${name}`); - const format: FieldFormatConfig = { - ...index.fieldFormatMap[name], - id: index.fieldFormatMap[name]?.id || 'date', // allow id: date_nanos - params: { - ...index.fieldFormatMap[name]?.params, - timezone: settings.timezone, - }, - }; - index.setFieldFormat(name, format); - }); - } catch (err) { - this.logger.error(err); - } + // apply timezone from the job to all date field formatters + try { + index.fields.getByType('date').forEach(({ name }) => { + this.logger.debug(`setting timezone on ${name}`); + const format: FieldFormatConfig = { + ...index.fieldFormatMap[name], + id: index.fieldFormatMap[name]?.id || 'date', // allow id: date_nanos + params: { + ...index.fieldFormatMap[name]?.params, + timezone: settings.timezone, + }, + }; + index.setFieldFormat(name, format); + }); + } catch (err) { + this.logger.error(err); } do { @@ -290,7 +298,7 @@ export class CsvGenerator { try { if (scrollId == null) { // open a scroll cursor in Elasticsearch - results = await this.search(searchSource, scrollSettings); + results = await this.scan(index, searchSource, scrollSettings); scrollId = results?._scroll_id; if (results.hits?.total != null) { totalRecords = results.hits.total; From 15feea4706fcb41bb8bc27f1a85e55daf1ef1dac Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 10:05:56 -0700 Subject: [PATCH 10/51] Revert "update docs" This reverts commit ab9f4d9642136fb0f53213dbe06037efaa89b6b9. --- ...in-plugins-data-public.searchsource.flatten.md | 15 --------------- ...ana-plugin-plugins-data-public.searchsource.md | 1 - src/plugins/data/public/public.api.md | 2 -- 3 files changed, 18 deletions(-) delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md deleted file mode 100644 index bf70f7b88f2fd..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.flatten.md +++ /dev/null @@ -1,15 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) > [flatten](./kibana-plugin-plugins-data-public.searchsource.flatten.md) - -## SearchSource.flatten() method - -Signature: - -```typescript -flatten(): Record; -``` -Returns: - -`Record` - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md index 1cee2e888fd40..b2382d35f7d76 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md @@ -34,7 +34,6 @@ export declare class SearchSource | [destroy()](./kibana-plugin-plugins-data-public.searchsource.destroy.md) | | Completely destroy the SearchSource. {undefined} | | [fetch(options)](./kibana-plugin-plugins-data-public.searchsource.fetch.md) | | Fetch this source and reject the returned Promise on error | | [fetch$(options)](./kibana-plugin-plugins-data-public.searchsource.fetch_.md) | | Fetch this source from Elasticsearch, returning an observable over the response(s) | -| [flatten()](./kibana-plugin-plugins-data-public.searchsource.flatten.md) | | | | [getField(field, recurse)](./kibana-plugin-plugins-data-public.searchsource.getfield.md) | | Gets a single field from the fields | | [getFields()](./kibana-plugin-plugins-data-public.searchsource.getfields.md) | | returns all search source fields | | [getId()](./kibana-plugin-plugins-data-public.searchsource.getid.md) | | returns search source id | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 0f5c275f9c919..9720395881ea3 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2389,8 +2389,6 @@ export class SearchSource { fetch$(options?: ISearchOptions): import("rxjs").Observable>; // @deprecated fetch(options?: ISearchOptions): Promise>; - // (undocumented) - flatten(): Record; getField(field: K, recurse?: boolean): SearchSourceFields[K]; getFields(): SearchSourceFields; getId(): string; From 003f22252da4bf92a939d4c245536bff09674234 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 10:32:03 -0700 Subject: [PATCH 11/51] optimize some async calls --- .../csv_searchsource/execute_job.ts | 17 ++++++++++------- .../csv_searchsource_immediate/execute_job.ts | 16 +++++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts index 07c68f22c2f4f..ff50377ab13c5 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/execute_job.ts @@ -24,19 +24,22 @@ export const runTaskFnFactory: RunTaskFnFactory> = ( const encryptionKey = config.get('encryptionKey'); const headers = await decryptJobHeaders(encryptionKey, job.headers, logger); const fakeRequest = reporting.getFakeRequest({ headers }, job.spaceId, logger); - const uiSettingsClient = await reporting.getUiSettingsClient(fakeRequest, logger); + const uiSettings = await reporting.getUiSettingsClient(fakeRequest, logger); const dataPluginStart = await reporting.getDataService(); - const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( - uiSettingsClient - ); + const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory(uiSettings); + + const [es, searchSourceStart] = await Promise.all([ + (await reporting.getEsClient()).asScoped(fakeRequest), + await dataPluginStart.search.searchSource.asScoped(fakeRequest), + ]); const clients = { - uiSettings: uiSettingsClient, + uiSettings, data: dataPluginStart.search.asScoped(fakeRequest), - es: (await reporting.getEsClient()).asScoped(fakeRequest), + es, }; const dependencies = { - searchSourceStart: await dataPluginStart.search.searchSource.asScoped(fakeRequest), + searchSourceStart, fieldFormatsRegistry, }; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts index 0a6f806b4e8b2..c8475e85bd847 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource_immediate/execute_job.ts @@ -39,20 +39,22 @@ export const runTaskFnFactory: RunTaskFnFactory = function e }; const savedObjectsClient = context.core.savedObjects.client; - const uiSettingsClient = await reporting.getUiSettingsServiceFactory(savedObjectsClient); + const uiSettings = await reporting.getUiSettingsServiceFactory(savedObjectsClient); const dataPluginStart = await reporting.getDataService(); - const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory( - uiSettingsClient - ); + const fieldFormatsRegistry = await getFieldFormats().fieldFormatServiceFactory(uiSettings); + const [es, searchSourceStart] = await Promise.all([ + (await reporting.getEsClient()).asScoped(req), + await dataPluginStart.search.searchSource.asScoped(req), + ]); const clients = { - uiSettings: uiSettingsClient, + uiSettings, data: dataPluginStart.search.asScoped(req), - es: (await reporting.getEsClient()).asScoped(req), + es, }; const dependencies = { fieldFormatsRegistry, - searchSourceStart: await dataPluginStart.search.searchSource.asScoped(req), + searchSourceStart, }; const cancellationToken = new CancellationToken(); From 59c91b72016beb47563f57b57c4664df20964c2f Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 10:54:47 -0700 Subject: [PATCH 12/51] cleanup --- src/plugins/data/common/search/search_source/mocks.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/data/common/search/search_source/mocks.ts b/src/plugins/data/common/search/search_source/mocks.ts index 7eb0d87c0b15c..ade22c20596d9 100644 --- a/src/plugins/data/common/search/search_source/mocks.ts +++ b/src/plugins/data/common/search/search_source/mocks.ts @@ -18,7 +18,6 @@ export const searchSourceInstanceMock: MockedKeys = { setFields: jest.fn().mockReturnThis(), setField: jest.fn().mockReturnThis(), removeField: jest.fn().mockReturnThis(), - flatten: jest.fn().mockImplementation(() => ({ body: {}, index: {} })), getId: jest.fn(), getFields: jest.fn(), getField: jest.fn(), From c15fe80c6eacbe8044fc00648e1ed5c27efc98cc Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 11:09:45 -0700 Subject: [PATCH 13/51] --wip-- [skip ci] --- .../schema/xpack_plugins.json | 176 ------------------ 1 file changed, 176 deletions(-) diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 8367fcb6deef2..4a0ab555f8f40 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -2436,16 +2436,6 @@ } } }, - "csv_searchsource": { - "properties": { - "available": { - "type": "boolean" - }, - "total": { - "type": "long" - } - } - }, "PNG": { "properties": { "available": { @@ -2531,19 +2521,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2587,19 +2564,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2643,19 +2607,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2699,19 +2650,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2755,19 +2693,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2811,19 +2736,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -2875,16 +2787,6 @@ } } }, - "csv_searchsource": { - "properties": { - "available": { - "type": "boolean" - }, - "total": { - "type": "long" - } - } - }, "PNG": { "properties": { "available": { @@ -2970,19 +2872,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -3026,19 +2915,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -3082,19 +2958,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -3138,19 +3001,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -3194,19 +3044,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { @@ -3250,19 +3087,6 @@ } } }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, "PNG": { "properties": { "canvas workpad": { From c1c0dda2358163a43ee0cbf887a9fa9055e6ba53 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 11:19:58 -0700 Subject: [PATCH 14/51] fix telemetry schema --- .../plugins/reporting/server/usage/schema.ts | 2 + .../plugins/reporting/server/usage/types.ts | 4 +- .../schema/xpack_plugins.json | 176 ++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/reporting/server/usage/schema.ts b/x-pack/plugins/reporting/server/usage/schema.ts index ec15ae4b1ac47..8528543b09e07 100644 --- a/x-pack/plugins/reporting/server/usage/schema.ts +++ b/x-pack/plugins/reporting/server/usage/schema.ts @@ -16,6 +16,7 @@ const appCountsSchema: MakeSchemaFrom = { const byAppCountsSchema: MakeSchemaFrom = { csv: appCountsSchema, + csv_searchsource: appCountsSchema, PNG: appCountsSchema, printable_pdf: appCountsSchema, }; @@ -27,6 +28,7 @@ const availableTotalSchema: MakeSchemaFrom = { const jobTypesSchema: MakeSchemaFrom = { csv: availableTotalSchema, + csv_searchsource: availableTotalSchema, PNG: availableTotalSchema, printable_pdf: { ...availableTotalSchema, diff --git a/x-pack/plugins/reporting/server/usage/types.ts b/x-pack/plugins/reporting/server/usage/types.ts index 5970df6ccae43..58def60a24ccb 100644 --- a/x-pack/plugins/reporting/server/usage/types.ts +++ b/x-pack/plugins/reporting/server/usage/types.ts @@ -59,7 +59,7 @@ export interface AvailableTotal { total: number; } -type BaseJobTypes = 'csv' | 'PNG' | 'printable_pdf'; +type BaseJobTypes = 'csv' | 'csv_searchsource' | 'PNG' | 'printable_pdf'; export interface LayoutCounts { print: number; preserve_layout: number; @@ -106,7 +106,7 @@ export type ReportingUsageType = RangeStats & { last7Days: RangeStats; }; -export type ExportType = 'csv' | 'printable_pdf' | 'PNG'; +export type ExportType = 'csv' | 'csv_searchsource' | 'printable_pdf' | 'PNG'; export type FeatureAvailabilityMap = { [F in ExportType]: boolean }; export interface KeyCountBucket { diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 4a0ab555f8f40..8367fcb6deef2 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -2436,6 +2436,16 @@ } } }, + "csv_searchsource": { + "properties": { + "available": { + "type": "boolean" + }, + "total": { + "type": "long" + } + } + }, "PNG": { "properties": { "available": { @@ -2521,6 +2531,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2564,6 +2587,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2607,6 +2643,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2650,6 +2699,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2693,6 +2755,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2736,6 +2811,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2787,6 +2875,16 @@ } } }, + "csv_searchsource": { + "properties": { + "available": { + "type": "boolean" + }, + "total": { + "type": "long" + } + } + }, "PNG": { "properties": { "available": { @@ -2872,6 +2970,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2915,6 +3026,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -2958,6 +3082,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3001,6 +3138,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3044,6 +3194,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { @@ -3087,6 +3250,19 @@ } } }, + "csv_searchsource": { + "properties": { + "canvas workpad": { + "type": "long" + }, + "dashboard": { + "type": "long" + }, + "visualization": { + "type": "long" + } + } + }, "PNG": { "properties": { "canvas workpad": { From 272823fb770a2a4983f7971f7d124979c92c073e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 11:27:05 -0700 Subject: [PATCH 15/51] fix telemetry tests --- .../server/usage/reporting_usage_collector.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts index 9335fee766740..037480ef38867 100644 --- a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -354,11 +354,13 @@ describe('data modeling', () => { available: true, browser_type: 'chromium', csv: { available: true, total: 4 }, + csv_searchsource: { available: true, total: 4 }, enabled: true, last7Days: { PNG: { available: true, total: 0 }, _all: 0, csv: { available: true, total: 0 }, + csv_searchsource: { available: true, total: 0 }, printable_pdf: { app: { dashboard: 0, visualization: 0 }, available: true, @@ -389,11 +391,13 @@ describe('data modeling', () => { available: true, browser_type: 'chromium', csv: { available: true, total: 0 }, + csv_searchsource: { available: true, total: 0 }, enabled: true, last7Days: { PNG: { available: true, total: 3 }, _all: 4, csv: { available: true, total: 0 }, + csv_searchsource: { available: true, total: 0 }, printable_pdf: { app: { 'canvas workpad': 1, dashboard: 0, visualization: 0 }, available: true, @@ -431,6 +435,7 @@ describe('data modeling', () => { layout: { preserve_layout: 0, print: 0 }, }, csv: { available: true, total: 0 }, + csv_searchsource: { available: true, total: 0 }, PNG: { available: true, total: 0 }, }, _all: 0, @@ -443,6 +448,7 @@ describe('data modeling', () => { layout: { preserve_layout: 0, print: 0 }, }, csv: { available: true, total: 0 }, + csv_searchsource: { available: true, total: 0 }, PNG: { available: true, total: 0 }, }); }); From 7d9dd58fcfd5fb77aaa4f158b85525b590a44d33 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 5 Mar 2021 14:18:55 -0700 Subject: [PATCH 16/51] fix snapshot --- .../usage/reporting_usage_collector.test.ts | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts index 037480ef38867..05b80bc8acc75 100644 --- a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -497,6 +497,14 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "available": Object { + "type": "boolean", + }, + "total": Object { + "type": "long", + }, + }, "enabled": Object { "type": "boolean", }, @@ -520,6 +528,14 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "available": Object { + "type": "boolean", + }, + "total": Object { + "type": "long", + }, + }, "printable_pdf": Object { "app": Object { "canvas workpad": Object { @@ -591,6 +607,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -626,6 +653,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -661,6 +699,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -696,6 +745,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -731,6 +791,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -766,6 +837,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -851,6 +933,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -886,6 +979,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -921,6 +1025,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -956,6 +1071,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -991,6 +1117,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", @@ -1026,6 +1163,17 @@ describe('Ready for collection observable', () => { "type": "long", }, }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, "printable_pdf": Object { "canvas workpad": Object { "type": "long", From 9b8251c777d4c58e0de78fb36385e7470228e6c2 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sun, 7 Mar 2021 11:54:10 -0700 Subject: [PATCH 17/51] api docs --- api_docs/data.json | 50 +++++------ api_docs/data_search.json | 177 ++++++++++++++++++++++++++++++++++++++ api_docs/discover.json | 19 ++++ api_docs/reporting.json | 114 +++++++++++++++++------- 4 files changed, 302 insertions(+), 58 deletions(-) diff --git a/api_docs/data.json b/api_docs/data.json index b639f5d6d2de7..1f104aba5e36d 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -21764,7 +21764,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 245 + "lineNumber": 246 }, "signature": [ "typeof ", @@ -21785,7 +21785,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 246 + "lineNumber": 247 }, "signature": [ "typeof ", @@ -21806,7 +21806,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 247 + "lineNumber": 248 }, "signature": [ "({ display: string; val: string; enabled(agg: ", @@ -21828,7 +21828,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 248 + "lineNumber": 249 }, "signature": [ "typeof ", @@ -21849,7 +21849,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 249 + "lineNumber": 250 }, "signature": [ "typeof ", @@ -21870,7 +21870,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 250 + "lineNumber": 251 }, "signature": [ "typeof ", @@ -21891,7 +21891,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 251 + "lineNumber": 252 }, "signature": [ "(agg: ", @@ -21913,7 +21913,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 252 + "lineNumber": 253 }, "signature": [ "(agg: ", @@ -21935,7 +21935,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 253 + "lineNumber": 254 }, "signature": [ "(...types: string[]) => (agg: ", @@ -21957,7 +21957,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 254 + "lineNumber": 255 }, "signature": [ "typeof ", @@ -21978,7 +21978,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 255 + "lineNumber": 256 }, "signature": [ "typeof ", @@ -21999,7 +21999,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 256 + "lineNumber": 257 } }, { @@ -22010,7 +22010,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 257 + "lineNumber": 258 }, "signature": [ "typeof ", @@ -22031,7 +22031,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 258 + "lineNumber": 259 }, "signature": [ "typeof ", @@ -22052,7 +22052,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 259 + "lineNumber": 260 }, "signature": [ "typeof ", @@ -22073,7 +22073,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 260 + "lineNumber": 261 } }, { @@ -22084,7 +22084,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 261 + "lineNumber": 262 }, "signature": [ "string[]" @@ -22098,7 +22098,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 262 + "lineNumber": 263 }, "signature": [ "typeof ", @@ -22119,7 +22119,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 263 + "lineNumber": 264 }, "signature": [ "typeof ", @@ -22137,7 +22137,7 @@ "label": "aggs", "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 244 + "lineNumber": 245 } }, { @@ -22148,7 +22148,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 265 + "lineNumber": 266 }, "signature": [ "typeof ", @@ -22169,7 +22169,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 266 + "lineNumber": 267 }, "signature": [ "typeof ", @@ -22190,7 +22190,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 267 + "lineNumber": 268 }, "signature": [ "typeof ", @@ -22211,7 +22211,7 @@ "description": [], "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 268 + "lineNumber": 269 }, "signature": [ "typeof ", @@ -22229,7 +22229,7 @@ "label": "search", "source": { "path": "src/plugins/data/server/index.ts", - "lineNumber": 243 + "lineNumber": 244 }, "initialIsOpen": false }, diff --git a/api_docs/data_search.json b/api_docs/data_search.json index bcf9e8819f347..399850c519a5c 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -1546,6 +1546,183 @@ } ], "interfaces": [ + { + "id": "def-server.IScopedSearchClient", + "type": "Interface", + "label": "IScopedSearchClient", + "signature": [ + { + "pluginId": "data", + "scope": "server", + "docId": "kibDataSearchPluginApi", + "section": "def-server.IScopedSearchClient", + "text": "IScopedSearchClient" + }, + " extends ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ISearchClient", + "text": "ISearchClient" + } + ], + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-server.IScopedSearchClient.saveSession", + "type": "Function", + "label": "saveSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 90 + }, + "signature": [ + "(sessionId: string, attributes: Partial) => Promise<", + { + "pluginId": "core", + "scope": "common", + "docId": "kibCorePluginApi", + "section": "def-common.SavedObject", + "text": "SavedObject" + }, + " | undefined>" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.getSession", + "type": "Function", + "label": "getSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 91 + }, + "signature": [ + "(sessionId: string) => Promise<", + { + "pluginId": "core", + "scope": "common", + "docId": "kibCorePluginApi", + "section": "def-common.SavedObject", + "text": "SavedObject" + }, + ">" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.findSessions", + "type": "Function", + "label": "findSessions", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 92 + }, + "signature": [ + "(options: Pick<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptions", + "text": "SavedObjectsFindOptions" + }, + ", \"filter\" | \"fields\" | \"searchAfter\" | \"search\" | \"page\" | \"perPage\" | \"sortField\" | \"sortOrder\" | \"searchFields\" | \"rootSearchFields\" | \"hasReference\" | \"hasReferenceOperator\" | \"defaultSearchOperator\" | \"namespaces\" | \"typeToNamespacesMap\" | \"preference\" | \"pit\">) => Promise<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindResponse", + "text": "SavedObjectsFindResponse" + }, + ">" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.updateSession", + "type": "Function", + "label": "updateSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 93 + }, + "signature": [ + "(sessionId: string, attributes: Partial) => Promise<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsUpdateResponse", + "text": "SavedObjectsUpdateResponse" + }, + ">" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.cancelSession", + "type": "Function", + "label": "cancelSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 94 + }, + "signature": [ + "(sessionId: string) => Promise<{}>" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.deleteSession", + "type": "Function", + "label": "deleteSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 95 + }, + "signature": [ + "(sessionId: string) => Promise<{}>" + ] + }, + { + "tags": [], + "id": "def-server.IScopedSearchClient.extendSession", + "type": "Function", + "label": "extendSession", + "description": [], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 96 + }, + "signature": [ + "(sessionId: string, expires: Date) => Promise<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsUpdateResponse", + "text": "SavedObjectsUpdateResponse" + }, + ">" + ] + } + ], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 89 + }, + "initialIsOpen": false + }, { "id": "def-server.ISearchSessionService", "type": "Interface", diff --git a/api_docs/discover.json b/api_docs/discover.json index 69e1d0366a712..adcecddfcc444 100644 --- a/api_docs/discover.json +++ b/api_docs/discover.json @@ -40,6 +40,25 @@ "lineNumber": 18 }, "initialIsOpen": false + }, + { + "id": "def-public.loadSharingDataHelpers", + "type": "Function", + "label": "loadSharingDataHelpers", + "signature": [ + "() => Promise" + ], + "description": [], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "src/plugins/discover/public/shared/index.ts", + "lineNumber": 12 + }, + "initialIsOpen": false } ], "interfaces": [ diff --git a/api_docs/reporting.json b/api_docs/reporting.json index 1296fb8926178..fe3a27fa8509e 100644 --- a/api_docs/reporting.json +++ b/api_docs/reporting.json @@ -851,7 +851,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 58 + "lineNumber": 62 } } ], @@ -859,7 +859,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 58 + "lineNumber": 62 } }, { @@ -895,7 +895,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 63 + "lineNumber": 67 } } ], @@ -903,7 +903,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 63 + "lineNumber": 67 } }, { @@ -939,7 +939,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 71 + "lineNumber": 75 } } ], @@ -947,7 +947,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 71 + "lineNumber": 75 } }, { @@ -963,7 +963,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 79 + "lineNumber": 83 } }, { @@ -979,7 +979,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 90 + "lineNumber": 94 } }, { @@ -995,7 +995,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 97 + "lineNumber": 101 } }, { @@ -1031,7 +1031,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 104 + "lineNumber": 108 } } ], @@ -1039,7 +1039,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 104 + "lineNumber": 108 } }, { @@ -1057,7 +1057,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 112 + "lineNumber": 116 } }, { @@ -1080,7 +1080,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 132 + "lineNumber": 136 } }, { @@ -1104,7 +1104,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 142 + "lineNumber": 146 } }, { @@ -1127,7 +1127,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 150 + "lineNumber": 154 } }, { @@ -1151,7 +1151,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 154 + "lineNumber": 158 } }, { @@ -1175,7 +1175,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 158 + "lineNumber": 162 } }, { @@ -1199,7 +1199,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 168 + "lineNumber": 172 } }, { @@ -1222,7 +1222,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 177 + "lineNumber": 181 } }, { @@ -1245,7 +1245,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 184 + "lineNumber": 189 } }, { @@ -1291,7 +1291,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 193 + "lineNumber": 198 } } ], @@ -1299,7 +1299,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 193 + "lineNumber": 198 } }, { @@ -1344,7 +1344,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 199 + "lineNumber": 204 } }, { @@ -1363,7 +1363,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 199 + "lineNumber": 204 } } ], @@ -1371,7 +1371,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 199 + "lineNumber": 204 } }, { @@ -1409,7 +1409,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 213 + "lineNumber": 218 } }, { @@ -1422,7 +1422,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 213 + "lineNumber": 218 } }, { @@ -1441,7 +1441,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 213 + "lineNumber": 218 } } ], @@ -1449,7 +1449,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 213 + "lineNumber": 218 } }, { @@ -1502,7 +1502,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 233 + "lineNumber": 238 } }, { @@ -1521,7 +1521,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 233 + "lineNumber": 238 } } ], @@ -1529,13 +1529,61 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 233 + "lineNumber": 238 + } + }, + { + "id": "def-server.ReportingCore.getDataService", + "type": "Function", + "label": "getDataService", + "signature": [ + "() => Promise<", + { + "pluginId": "data", + "scope": "server", + "docId": "kibDataPluginApi", + "section": "def-server.DataPluginStart", + "text": "DataPluginStart" + }, + ">" + ], + "description": [], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "x-pack/plugins/reporting/server/core.ts", + "lineNumber": 248 + } + }, + { + "id": "def-server.ReportingCore.getEsClient", + "type": "Function", + "label": "getEsClient", + "signature": [ + "() => Promise<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCorePluginApi", + "section": "def-server.IClusterClient", + "text": "IClusterClient" + }, + ">" + ], + "description": [], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "x-pack/plugins/reporting/server/core.ts", + "lineNumber": 253 } } ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 50 + "lineNumber": 54 }, "initialIsOpen": false }, From c5d342181ac14ac6dddca0f89629383d5040f630 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 8 Mar 2021 17:53:20 -0700 Subject: [PATCH 18/51] api doc updates --- api_docs/reporting.json | 132 +++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/api_docs/reporting.json b/api_docs/reporting.json index d06f068f56624..44050591f71cb 100644 --- a/api_docs/reporting.json +++ b/api_docs/reporting.json @@ -851,7 +851,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 65 + "lineNumber": 69 } }, { @@ -873,7 +873,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 65 + "lineNumber": 69 } } ], @@ -881,7 +881,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 65 + "lineNumber": 69 } }, { @@ -917,7 +917,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 75 + "lineNumber": 79 } } ], @@ -925,7 +925,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 75 + "lineNumber": 79 } }, { @@ -961,7 +961,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 89 + "lineNumber": 93 } } ], @@ -969,7 +969,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 89 + "lineNumber": 93 } }, { @@ -985,7 +985,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 102 + "lineNumber": 106 } }, { @@ -1001,7 +1001,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 113 + "lineNumber": 117 } }, { @@ -1017,7 +1017,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 120 + "lineNumber": 124 } }, { @@ -1053,7 +1053,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 127 + "lineNumber": 131 } } ], @@ -1061,7 +1061,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 127 + "lineNumber": 131 } }, { @@ -1079,7 +1079,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 135 + "lineNumber": 139 } }, { @@ -1102,7 +1102,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 155 + "lineNumber": 159 } }, { @@ -1126,7 +1126,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 165 + "lineNumber": 169 } }, { @@ -1149,7 +1149,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 173 + "lineNumber": 177 } }, { @@ -1210,7 +1210,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 177 + "lineNumber": 181 } } ], @@ -1218,7 +1218,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 177 + "lineNumber": 181 } }, { @@ -1242,7 +1242,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 181 + "lineNumber": 185 } }, { @@ -1266,7 +1266,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 185 + "lineNumber": 189 } }, { @@ -1290,7 +1290,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 195 + "lineNumber": 199 } }, { @@ -1313,7 +1313,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 204 + "lineNumber": 208 } }, { @@ -1336,7 +1336,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 211 + "lineNumber": 216 } }, { @@ -1382,7 +1382,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 220 + "lineNumber": 225 } } ], @@ -1390,7 +1390,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 220 + "lineNumber": 225 } }, { @@ -1435,7 +1435,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 226 + "lineNumber": 231 } }, { @@ -1454,7 +1454,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 226 + "lineNumber": 231 } } ], @@ -1462,7 +1462,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 226 + "lineNumber": 231 } }, { @@ -1500,7 +1500,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 240 + "lineNumber": 245 } }, { @@ -1513,7 +1513,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 240 + "lineNumber": 245 } }, { @@ -1532,7 +1532,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 240 + "lineNumber": 245 } } ], @@ -1540,7 +1540,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 240 + "lineNumber": 245 } }, { @@ -1593,7 +1593,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 260 + "lineNumber": 265 } }, { @@ -1612,7 +1612,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 260 + "lineNumber": 265 } } ], @@ -1620,7 +1620,55 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 260 + "lineNumber": 265 + } + }, + { + "id": "def-server.ReportingCore.getDataService", + "type": "Function", + "label": "getDataService", + "signature": [ + "() => Promise<", + { + "pluginId": "data", + "scope": "server", + "docId": "kibDataPluginApi", + "section": "def-server.DataPluginStart", + "text": "DataPluginStart" + }, + ">" + ], + "description": [], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "x-pack/plugins/reporting/server/core.ts", + "lineNumber": 275 + } + }, + { + "id": "def-server.ReportingCore.getEsClient", + "type": "Function", + "label": "getEsClient", + "signature": [ + "() => Promise<", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCorePluginApi", + "section": "def-server.IClusterClient", + "text": "IClusterClient" + }, + ">" + ], + "description": [], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "x-pack/plugins/reporting/server/core.ts", + "lineNumber": 280 } }, { @@ -1642,7 +1690,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 270 + "lineNumber": 285 } } ], @@ -1650,7 +1698,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 270 + "lineNumber": 285 } }, { @@ -1672,7 +1720,7 @@ "description": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 274 + "lineNumber": 289 } } ], @@ -1680,7 +1728,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 274 + "lineNumber": 289 } }, { @@ -1696,13 +1744,13 @@ "returnComment": [], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 278 + "lineNumber": 293 } } ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 54 + "lineNumber": 58 }, "initialIsOpen": false }, @@ -2437,4 +2485,4 @@ } ] } -} +} \ No newline at end of file From 7852a430e17337ac159d9ba7eed59ebd17524e88 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 10 Mar 2021 11:03:00 -0700 Subject: [PATCH 19/51] use import type --- .../discover/public/application/helpers/get_sharing_data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 11b2309df305e..2f5d550178990 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -11,7 +11,7 @@ import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../ import { getSortForSearchSource } from '../angular/doc_table'; import { ISearchSource } from '../../../../data/common'; import { AppState } from '../angular/discover_state'; -import { SavedSearch, SortOrder } from '../../saved_searches/types'; +import type { SavedSearch, SortOrder } from '../../saved_searches/types'; /** * Preparing data to share the current state as link or CSV/Report From a5c31159274648281cbe21b3530a7122279e8d22 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 10 Mar 2021 12:23:15 -0700 Subject: [PATCH 20/51] format the data through chains of maps --- .../generate_csv/generate_csv.ts | 111 +++++++++--------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 7d6a53c90ab4c..8e68a74d38209 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; import { IScopedSearchClient } from 'src/plugins/data/server'; -import { Datatable } from 'src/plugins/expressions/server'; +import { Datatable, DatatableColumn, DatatableRow } from 'src/plugins/expressions/server'; import { ReportingConfig } from '../../..'; import { ES_SEARCH_STRATEGY, @@ -134,6 +134,53 @@ export class CsvGenerator { return this._formatters; } + private checkForFormulas(settings: CsvExportSettings) { + return (value: string) => { + if (settings.checkForFormulas && cellHasFormulas(value)) { + this.csvContainsFormulas = true; // set warning if cell value has a formula + } + return settings.escapeValue(value); + }; + } + + private getColumnName(fields: SearchFieldValue[] | undefined, table: Datatable) { + return (columnIndex: number, position: number) => { + let cell: string; + if (columnIndex > -1) { + cell = table.columns[columnIndex].name; + } else { + cell = fields && fields[position] ? (fields[position] as string) : 'unknown'; + } + return cell; + }; + } + + private tryToParseCellValues( + formatters: Record, + dataTableRow: DatatableRow + ) { + return (tableColumn: DatatableColumn) => { + let cell: string[] | string = formatters[tableColumn.id].convert( + dataTableRow[tableColumn.id] + ); + + try { + // expected values are a string of JSON where the value(s) is in an array + cell = JSON.parse(cell); + } catch (e) { + // ignore + } + + // We have to strip singular array values out of their array wrapper, + // So that the value appears the visually the same as seen in Discover + if (Array.isArray(cell)) { + cell = cell.join(', '); // mimic Discover behavior + } + + return cell; + }; + } + /* * Use the list of fields to generate the header row */ @@ -143,27 +190,14 @@ export class CsvGenerator { builder: MaxSizeStringBuilder, settings: CsvExportSettings ) { - const { checkForFormulas, escapeValue, separator } = settings; + this.logger.debug(`Building CSV header row...`); const columnMap = this.getColumnMap(fields, table); - this.logger.debug(`Building CSV header row...`); const header = columnMap - .map((columnIndex, position) => { - let value: string; - if (columnIndex > -1) { - value = table.columns[columnIndex].name; - } else { - value = fields && fields[position] ? (fields[position] as string) : 'unknown'; - } - - if (checkForFormulas && cellHasFormulas(value)) { - this.csvContainsFormulas = true; // set warning if heading value has a formula - } - - return escapeValue(value); - }) - .join(separator) + `\n`; + .map(this.getColumnName(fields, table)) + .map(this.checkForFormulas(settings)) + .join(settings.separator) + `\n`; if (!builder.tryAppend(header)) { return { @@ -185,51 +219,20 @@ export class CsvGenerator { formatters: Record, settings: CsvExportSettings ) { - // write the rows this.logger.debug(`Building ${table.rows.length} CSV data rows...`); - const { checkForFormulas, escapeValue, separator } = settings; + const columnMap = this.getColumnMap(fields, table); for (const dataTableRow of table.rows) { if (this.cancellationToken.isCancelled()) { break; } - const columnMap = this.getColumnMap(fields, table); const row = columnMap - .map((columnIndex, position) => { - const tableColumn = table.columns[columnIndex]; - let cell: string[] | string = '-'; - - if (tableColumn != null) { - cell = formatters[tableColumn.id].convert(dataTableRow[tableColumn.id]); - - try { - // expected values are a string of JSON where the value(s) is in an array - cell = JSON.parse(cell); - } catch (e) { - // ignore - } - - // We have to strip singular array values out of their array wrapper, - // So that the value appears the visually the same as seen in Discover - if (Array.isArray(cell)) { - cell = cell.join(', '); // mimic Discover behavior - } - } else { - this.logger.warn(`Unrecognized field: ${(fields && fields[position]) || 'unknown'}`); - } - - return cell; - }) - .map((value) => { - if (checkForFormulas && cellHasFormulas(value)) { - this.csvContainsFormulas = true; // set warning if cell value has a formula - } - // Escape the values in Data - return escapeValue(value); - }) - .join(separator) + '\n'; + .map((columnIndex) => table.columns[columnIndex]) + .map(this.tryToParseCellValues(formatters, dataTableRow)) + .map(this.checkForFormulas(settings)) + .join(settings.separator) + '\n'; if (!builder.tryAppend(row)) { this.logger.warn('max Size Reached'); From 6edf26eff255189c4a2c88a93a327497bd833410 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 10:42:06 -0700 Subject: [PATCH 21/51] add another saved search to reporting/ecommerce_kibana --- .../reporting/ecommerce/data.json.gz | Bin 957893 -> 956882 bytes .../reporting/ecommerce_kibana/data.json | 30 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz b/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz index 7736287bc9a37e5203c887d89bcfbe7d98fe1dd9..dccdf85fcb0c7085ec38ea137214aa0474423ebf 100644 GIT binary patch delta 58013 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 delta 59032 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 aYUPK@`ti!#h{gQ_LMGQ5w^2qL!v6rllKrRv diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json index a0f384a96e6b4..71e2d5bd05c95 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json @@ -29,3 +29,33 @@ { "type": "doc", "value": { "id": "visualization:1bba55f0-507e-11eb-9c0d-97106882b997", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "search_0", "type": "search" } ], "type": "visualization", "updated_at": "2021-01-07T00:23:04.624Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" }, "savedSearchRefName": "search_0", "title": "Tag Cloud of Names", "uiStateJSON": "{}", "version": 1, "visState": "{\"title\":\"Tag Cloud of Names\",\"type\":\"tagcloud\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"customer_first_name.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true}}" } } } } { "type": "doc", "value": { "id": "ui-counter:DashboardPanelVersionInUrl:06012021:loaded:8.0.0", "index": ".kibana_1", "source": { "type": "ui-counter", "ui-counter": { "count": 85 }, "updated_at": "2021-01-07T00:23:25.741Z" } } } + +{ + "type": "doc", + "value": { + "id": "search:357825a0-8290-11eb-b8f1-15ed8d3eeaaf", + "index": ".kibana_1", + "source": { + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "search": { + "columns": [ "_id", "order_id", "geoip" ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ [ "order_date", "desc" ] ], + "title": "ECommerce - GEOIP Data", + "version": 1 + }, + "type": "search", + "updated_at": "2021-03-11T17:35:44.894Z" + } + } +} From 53ed8afecf2f101a921dbe90d17fc49f11a851dd Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 12:14:40 -0700 Subject: [PATCH 22/51] add a failing test --- .../discover/__snapshots__/reporting.snap | 4 ++ .../functional/apps/discover/reporting.ts | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 3c2fd087cfd66..728a2e1c42335 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,5 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`discover Discover Generate CSV: Fields From Source limitation With using fieldsFromSource, it generates a report that does not have GEOIP data 1`] = `"FIXME"`; + +exports[`discover Discover Generate CSV: Fields From Source limitation Without using fieldsFromSource, it generates a report with GEOIP data 1`] = `"FIXME"`; + exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index dfc44a8e0e12d..3949a0761688d 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -12,6 +12,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const es = getService('es'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const browser = getService('browser'); const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker']); const filterBar = getService('filterBar'); @@ -148,5 +149,59 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expectSnapshot(res.text).toMatch(); }); }); + + describe('Generate CSV: Fields From Source limitation', () => { + before(async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + }); + + after(async () => { + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); + + afterEach(async () => { + await kibanaServer.uiSettings.replace({}); + }); + + beforeEach(() => PageObjects.common.navigateToApp('discover')); + + it('With using fieldsFromSource, it generates a report that does not have GEOIP data', async () => { + await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': true }); + await PageObjects.discover.loadSavedSearch('ECommerce - GEOIP Data'); + const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; + const toTime = 'Aug 23, 2019 @ 16:18:51.821'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.reporting.openCsvReportingPanel(); + await PageObjects.reporting.clickGenerateReportButton(); + + const url = await PageObjects.reporting.getReportURL(60000); + const res = await PageObjects.reporting.getResponse(url); + + expect(res.status).to.equal(200); + expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); + expectSnapshot(res.text).toMatch(); + }); + + it('Without using fieldsFromSource, it generates a report with GEOIP data', async () => { + await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': false }); + await PageObjects.discover.loadSavedSearch('ECommerce - GEOIP Data'); + const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; + const toTime = 'Aug 23, 2019 @ 16:18:51.821'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.reporting.openCsvReportingPanel(); + await PageObjects.reporting.clickGenerateReportButton(); + + const url = await PageObjects.reporting.getReportURL(60000); + const res = await PageObjects.reporting.getResponse(url); + + expect(res.status).to.equal(200); + expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); + expectSnapshot(res.text).toMatch(); + }); + }); }); } From e731e71d0c30b613adfa35a1a782293e06b8a8a1 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 12:15:02 -0700 Subject: [PATCH 23/51] add error logging to query failures --- src/plugins/data/server/search/es_search/es_search_strategy.ts | 3 +++ .../plugins/data_enhanced/server/search/es_search_strategy.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index cc81dce94c4ec..f0ae60139334c 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -49,6 +49,9 @@ export const esSearchStrategyProvider = ( const response = shimHitsTotal(body, options); return toKibanaSearchResponse(response); } catch (e) { + if (e.body.error) { + logger.error(e.body.error); + } throw getKbnServerError(e); } }; diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts index fc1cc63146358..4c02ef0d49bd0 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts @@ -84,6 +84,9 @@ export const enhancedEsSearchStrategyProvider = ( tap((response) => (id = response.id)), tap(searchUsageObserver(logger, usage)), catchError((e) => { + if (e.body.error) { + logger.error(e.body.error); + } throw getKbnServerError(e); }) ); From 4e896e75128105bfd0547cc1d30c52f7102a92fe Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 12:37:43 -0700 Subject: [PATCH 24/51] put clear scroll in a finally so the ES error can be captured --- .../generate_csv/generate_csv.ts | 112 +++++++++--------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 8e68a74d38209..ab1127d94039a 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -293,12 +293,12 @@ export class CsvGenerator { this.logger.error(err); } - do { - if (this.cancellationToken.isCancelled()) { - break; - } - let results: SearchResponse | undefined; - try { + try { + do { + if (this.cancellationToken.isCancelled()) { + break; + } + let results: SearchResponse | undefined; if (scrollId == null) { // open a scroll cursor in Elasticsearch results = await this.scan(index, searchSource, scrollSettings); @@ -311,70 +311,68 @@ export class CsvGenerator { // use the scroll cursor in Elasticsearch results = await this.scroll(scrollId, scrollSettings); } - } catch (err) { - this.logger.error(err); - } - if (!results) { - this.logger.warning(`Search results are undefined!`); - break; - } + if (!results) { + this.logger.warning(`Search results are undefined!`); + break; + } - let table: Datatable | undefined; - try { - table = tabifyDocs(results, index, { shallow: true, meta: true }); - } catch (err) { - this.logger.error(err); - } + let table: Datatable | undefined; + try { + table = tabifyDocs(results, index, { shallow: true, meta: true }); + } catch (err) { + this.logger.error(err); + } - if (!table) { - break; - } + if (!table) { + break; + } - // write the header and initialize formatters / column orderings - // depends on the table to know what order to place the columns - if (first) { - first = false; - this.generateHeader(fields, table, builder, settings); - } + // write the header and initialize formatters / column orderings + // depends on the table to know what order to place the columns + if (first) { + first = false; + this.generateHeader(fields, table, builder, settings); + } - if (table.rows.length < 1) { - break; // empty report with just the header - } + if (table.rows.length < 1) { + break; // empty report with just the header + } + + const formatters = this.getFormatters(table); + this.generateRows(fields, table, builder, formatters, settings); - const formatters = this.getFormatters(table); - this.generateRows(fields, table, builder, formatters, settings); + // update iterator + currentRecord += table.rows.length; + } while (currentRecord < totalRecords - 1); - // update iterator - currentRecord += table.rows.length; - } while (currentRecord < totalRecords - 1); + // Add warnings to be logged + if (this.csvContainsFormulas && escapeFormulaValues) { + warnings.push( + i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues', { + defaultMessage: 'CSV may contain formulas whose values have been escaped', + }) + ); + } + } finally { + // clear scrollID + if (scrollId) { + this.logger.debug(`executing clearScroll request`); + try { + await this.clients.es.asCurrentUser.clearScroll({ scroll_id: [scrollId] }); + } catch (err) { + this.logger.error(err); + } + } else { + this.logger.warn(`No scrollId to clear!`); + } + } const size = builder.getSizeInBytes(); this.logger.debug( `Finished generating. Total size in bytes: ${size}. Row count: ${this.csvRowCount}.` ); - // Add warnings to be logged - if (this.csvContainsFormulas && escapeFormulaValues) { - warnings.push( - i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues', { - defaultMessage: 'CSV may contain formulas whose values have been escaped', - }) - ); - } - - // clear scrollID - if (scrollId) { - this.logger.debug(`executing clearScroll request`); - try { - await this.clients.es.asCurrentUser.clearScroll({ scroll_id: [scrollId] }); - } catch (err) { - this.logger.error(err); - } - } else { - this.logger.warn(`No scrollId to clear!`); - } - return { content: builder.getString(), content_type: CONTENT_TYPE_CSV, From 5e6ebc53c7fc5f8808f6deadcea1e54b2af29479 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 13:26:44 -0700 Subject: [PATCH 25/51] log dat error --- .../export_types/csv_searchsource/generate_csv/generate_csv.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index ab1127d94039a..819e931792c6e 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -354,6 +354,8 @@ export class CsvGenerator { }) ); } + } catch (err) { + this.logger.error(err); } finally { // clear scrollID if (scrollId) { From 74dd22692db1699b1385ae56981b76a836ef4d60 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 13:29:22 -0700 Subject: [PATCH 26/51] set dat fieldsFromSource --- .../application/helpers/get_sharing_data.ts | 20 ++++++++++-------- .../generate_csv/generate_csv.ts | 21 +++++++++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 2f5d550178990..8b08004f41ad6 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -23,6 +23,10 @@ export async function getSharingData( ) { const searchSource = currentSearchSource.createCopy(); const index = searchSource.getField('index')!; + const fields = { + fields: searchSource.getField('fields'), + fieldsFromSource: searchSource.getField('fieldsFromSource'), + }; searchSource.setField( 'sort', @@ -33,14 +37,13 @@ export async function getSharingData( searchSource.removeField('aggs'); searchSource.removeField('size'); - // Set the fields of the search source to match the saved search columns + // fields get re-set to match the saved search columns searchSource.removeField('fields'); searchSource.removeField('fieldsFromSource'); - let columns = state.columns || []; - // NOTE: A newly saved search with no columns selected has a bug(?) where the - // column array is a single '_source' value which is invalid for CSV export + // NOTE: A newly saved search with no columns selected will return a + // column array as a single '_source' value which is invalid for CSV export if (columns && columns.length === 1 && /^_source$/.test(columns.join())) { columns = []; } @@ -56,11 +59,10 @@ export async function getSharingData( columns = [timeFieldName, ...columns]; } - if (columns.length === 0) { - searchSource.setField('fields', ['*']); - } else { - searchSource.setField('fields', columns); - } + // if search source uses fieldsFromSource, set that + const fieldsKey = fields.fieldsFromSource ? 'fieldsFromSource' : 'fields'; + const fieldsValue = columns.length > 0 ? columns : ['*']; + searchSource.setField(fieldsKey, fieldsValue); return { searchSource: searchSource.getSerializedFields(true), diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 819e931792c6e..1ea8243f43785 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -143,6 +143,23 @@ export class CsvGenerator { }; } + private getFieldsFromSearchSource(searchSource: ISearchSource): SearchFieldValue[] { + let fields: string | boolean | SearchFieldValue[] | undefined = + searchSource.getField('fields') || searchSource.getField('fieldsFromSource'); + + if (fields === true || typeof fields === 'string') { + fields = [fields.toString()]; + } + if (fields == null) { + fields = ['undefined']; + } + if (!fields) { + fields = ['false']; + } + + return fields; + } + private getColumnName(fields: SearchFieldValue[] | undefined, table: Datatable) { return (columnIndex: number, position: number) => { let cell: string; @@ -264,8 +281,6 @@ export class CsvGenerator { throw new Error(`The search must have a revference to an index pattern!`); } - const fields = searchSource.getField('fields'); - const { maxSizeBytes, bom, escapeFormulaValues, scroll: scrollSettings } = settings; const builder = new MaxSizeStringBuilder(byteSizeValueToNumber(maxSizeBytes), bom); @@ -330,6 +345,8 @@ export class CsvGenerator { // write the header and initialize formatters / column orderings // depends on the table to know what order to place the columns + const fields = this.getFieldsFromSearchSource(searchSource); + if (first) { first = false; this.generateHeader(fields, table, builder, settings); From a7bcb9cbf60d700b624444364cd68aa3db50f537 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 15:06:49 -0700 Subject: [PATCH 27/51] --wip-- [skip ci] --- .../functional/apps/discover/reporting.ts | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 3949a0761688d..02eb4ab4a5ec3 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -20,6 +20,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Discover', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); + // FIXME: should also use reporting/ecommerce_kibana + // reporting/ecommerce needs to have the kibana object cleared out await esArchiver.loadIfNeeded('reporting/ecommerce'); await browser.setWindowSize(1600, 850); }); @@ -169,25 +171,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('With using fieldsFromSource, it generates a report that does not have GEOIP data', async () => { await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': true }); - await PageObjects.discover.loadSavedSearch('ECommerce - GEOIP Data'); - const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; - const toTime = 'Aug 23, 2019 @ 16:18:51.821'; - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); - - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); - - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - expectSnapshot(res.text).toMatch(); - }); - - it('Without using fieldsFromSource, it generates a report with GEOIP data', async () => { - await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': false }); - await PageObjects.discover.loadSavedSearch('ECommerce - GEOIP Data'); + await PageObjects.discover.loadSavedSearch('ECommerce Data'); const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; const toTime = 'Aug 23, 2019 @ 16:18:51.821'; await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); From 25844605d4c9a8c707d913bf82ca607a741199f0 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 15:06:51 -0700 Subject: [PATCH 28/51] Revert "add another saved search to reporting/ecommerce_kibana" This reverts commit 6edf26eff255189c4a2c88a93a327497bd833410. --- .../reporting/ecommerce/data.json.gz | Bin 956882 -> 957893 bytes .../reporting/ecommerce_kibana/data.json | 30 ------------------ 2 files changed, 30 deletions(-) diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz b/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz index dccdf85fcb0c7085ec38ea137214aa0474423ebf..7736287bc9a37e5203c887d89bcfbe7d98fe1dd9 100644 GIT binary patch delta 59032 zcmX_nV|ZO%*L7^8u^Ti_+N3cXqj4JBZpC)>?aF z%rVBCZs6(v#e+Z=fq*bQsio(K5QG33ga8$U03Cz?6NCU8ga8+W03U<^{vR<20VxOp zIS2uz2>}(W4X|=u;Yt<=@67q$Jy)|r5A}PJK`&mqoj!Xa>~q%4!I+(eB9;wXvKTsb z|K3y0yQ?4soff6T3QUc(`#4H5uRo%JRlsvMh)*j^PdN&|XNtTvu~#%o$M=*Xv4lm5 zdb}lt8J4phdUtGLEGfO!^hil%UV7AXX=r# ztD%EFr2cXyB>S;1A{PoKEHUZ$f&2Ty3f0EV4Eq{kE3`LM@u9w#@YY?ojzTK|6QuB; zIQnx$I2e8i?}!B=PZ_);&l#VYdl>!NIdS5qi_O~?0gd;xa&BEhN|Am-on%+O(-iOC zz~I!Wc3^q0sC=xzrv^g-KlVKc^RZ1L$bI0O&ke;a_6~#NA>>_3&dltaA%M~v`^;Z) zIF)A4NWdPZ^2+XmK72Fef8XL7#jBS*`!3s?h@*s#?h}Uwn4Kk~m&Zh^D}HRJQKGZG3i?03;eGj=7_p z;gdVgQ8GffI847MYgSN|dBD(1WV2U@zo_auHVOe8gg*XFFmlp04AT z`9qVX_syJ6FyhlM=7gH*Vzujf{L4{J-G%0IAN*x&)~52c+S7SI&mj3H#X==1_%88@ zNsFO}g-*43^1NL>cXo0CC-GT3{ zg(21uw~o%!QcVuOHm_g>Z_`*7EkhsJzn@Q^so}&isYjn4Xynuvs7rd2ZTe}6%r~pQ zyhQtMSa()ALS_A3@9BlJW@Vz{pX8?tWt*l#Ps?AYdmD(n-ArWpeFjqpB4_F+v)Qm> zN(f}Pw%+D|%*MGJZ}{cRS931y00o4g4hVp{HT02g`-bjR7+HN=?eGjXFe~UDH3E^! z(O%fO8E&slvrHnOJ00sE_L#rN-?B^&TPE?(EleRigD<3DgVWkTUb|_XF1?w5)d)D@1`OTMQ=VfttPWVN=T}0xrCiHz`vE1&@24Je( zYT*do{u-T?2L)Zx%h3scS=pLb(!@u{_jT{!rSecgq-y{i$=JKWeNwU-F66W z=OKN5|LU_Qe9$+BxTtax*%4|g2xclD`JMQ?ZUZ6` zB(`ub&eUVtPSk3bKHnt-H~XMt>g3M1~M~4t(;J4VIXe+^iJ6AkL>1=zt70Q^Ai^sJl{WP0n^`&d(8s-g zq_?X3nLqG0k(tkHyjK^pTh14po)2{52P=Zmwn$8;M`8v;7K!&MbeeO#{Gxr=&rbHu zFX44o5YD_uhDH-<0Ocd4cbFnb=(( zEfd!ZC=4z%6!aP-M`HY7W$Tb=BzQF8X**M==F~{UCMx)zzJ;*16T=qN_aEX;iauZVc??J70X?=y=G#4F4c2iq1M-4o z&yYlspK)7J?bDD}Bb(b_k-$0fo%P`$2%;yomgT|q*YovcavC%X?>LN#&Vpu0aA%Qb z4OyC@PJf$w1BQA8O#k1>jpYAHlg{IC$SKhww7I z%Fx#=4b|BW$lI$-ORspaO*V`Vq?<&TRY(oj*!@BylK)Clt02FNm077UvETTI7V?GX zAjK2-`-sd7PP=D{@i4JVR7T0(n9ed{79k>H+({^%j(OpJc|a44bRg z$OREY5EhJAmbrISPK;LL!X(_yBfw%Hd;~?3*F6r5&QG*h@3n|*8iK-z6uy0$=49rZ zP2=ne5=hU7pu)wK^~A9@ibf1zs^Qb4F9FNEcS6%b`?ncr-%a!rF67{vsOH^{oI>ozp z#{2+HOpMfPE30#ET{jnVWznZ?v&KMVv64z~crl|uM0e+Y9o($gvm+q6i^ZbLj|bT% zP+WZe<4i(V=vW!^E2z386A6`6K97+=;qE1RbCYUm_A#CbN!&kJ;k=ic_}IO4y2tta zzJWHBcl5Q{uflIl+X>=*U@?l%IQ+MQ)B)fRx#abdnc$e=o8Cp?X&7<+=!U4m;}b|I zpOSH}7pC#@^1|;ET7`O@QMp4l*_c`nl9_ZB;l%%S(|F_suKRw(b8@HR(Z{-fe)pNb zq!sHc;W1jsRxz;Uv#a&CNQYtiB_1uOo3*rr`N>SW@PU)x^lOkf`5_ID`W`=I9*}|R zYwMyn6{UHUtf+;K=*=JG#9|t;Mjw+Rb)~OkuBh$ae0!@QaaZZ@7~Kmf-2Igz-B2vD z^J;8!a|U^H?sW5uLMUEC%X#I*WTC$IF0!TIM# zYkE`Qb3fng$)isnoKZ@)8p|VrP1_C3e>H>I337aEbv?b8Wa-&uYYUjGT?NkkdYAhE zGCBsOgunKh$AU*lItlM=JtZxF?NI|jsy>8KH=Tt_~BBE z5v@G=MBwn_36Y!!>-nRf)1%MyfotF!XhtVXuugR&H^*ToCR#Da(`_!TK;SC&lei)V zU8MDSmLObhO)Xl*_BVQ+9dvr#B7-XNZ4?H9p_*Yhv9>Rm0= z89bc~^Ip(iz_^#UIHW%O2Z({V8T{+I5LwK-@}j)G8zEn#pqv@jF&fl>20_Ba-To}e zV{eXZ0eaJ-u#TmSd0d9-FAODx4)iU;rzsmSDR_$D>gzb_oqoybr1 zDEu7sB56Pm>^;c2@sXPq=aeZ?f5}P3!DZIlOVbh$@DbOVW%f5xS;xjWf$ZrJw%gLR zT-FNq$SQ`Uf4NNBR5WV6-;$Ed)AsjtioUgKUb19=`*OzbL@IEEl-1S2TVHmq)x1me zOOKadU@ZN`-(aKLZx-SXwi_o%zO)=k*f+ZTC3CW$Q&P$~_FoTW2WjOesU2*Z?;KpQi}(9LH4yo;~?!)R|)~fslN^QjZ*&NqfKcw zch;gwt##sXe_@UWOR^EQsE-2MW@E1qoAF1@3cdS391hDb)VOfMv?w#~^Go4E2mK?E z1@FOUMdqOQI8*Xk!XN7n3tHcFm_7bwdMMyc~R#9exx8sak(1Q+VX^EIj9xv&cAzoE5Go< zq-!($yhz-0grBj8d1Ntt-5~=A@tMH!e6AO9r5!Oy349UUyAvtXXgG}ZfwoHqr1Dy zYPB`$ANW$KdLT|#vw>(p9?xMnRyCqjOJA!vwMgcF|CzQ<>)z{+hAu`*6iH>Cg(EvJ z8Ys)AGpV+&3=!rH4otvWluA5kt1l(d>2Ug)FB+p5Yeh~C2S%U}S+tlUMc<1PKS0PP zoJ_EQBZdsf2M@BPdgaRksQ+k(CR^*@xla~w0 zY<->GmFcLy-!kyTcO(d{gk2!kbi)Nj_F@AeEf^npqv*)DsEX5t%0)FzM!JctgCd2z zS?4c>7J82U*POqcR_O9#Qtij!b`)xwQK1A2oL42jV2d@Mby}E?2a^mu4fj>ePHx0| zCGcq>-lJdJwg&k7tHm_Z_v5sFKUB zS$tp1kEVX!4SzU9dg%Ch$3GRc0o8>XmMKS(3k3832-gb?7|0g9i?zU@OaiE(xZWPP z<<1!6O?m3U6^y+X_cQmk2pz!>a0&D7(1jmNCit}Po ziwBZ7l;#$}*k1nGh(4TB`|O0nf8PfB(0qK~2J}OjV|*pGF{yl6e%k*GHWYPWqHBw% zIV@TY48RyAt&)dUvaKer1F8KZfZJHtD>g<}ti8O6trooNJlh z&@2Kv-JgW|e$dY}OTYG4R_MI#5QJlTlZ!i@4%mv^#eQmjJx=O~cSRrmpi+W7UtRM} zsdVhEG+{(<3tgk`S2k~5Kct}_41J;Hw=poSPzTbZ4w+(oZQEHRYm%$k`2{{)F6=T^L5iHC$R{(v!Qr;bc8io%lW?iXTa^ zHCMNn@SjU?LkvZuKn$3ZqE&@?@liPLRBM2HCt=AkBH=PlsAO3ZU%M1VL~-Wd{P_Jm z5OqK8?*Shz10hAv3D@M#vvGqpmFmS)J{-okgezQEbQnSq&hNNml$8e)|Rr1mf#%s2lb`B1y*L5P*A7z3(?T#JSK|#I|IX zfkJLp$}6LQx+)ToSK-v~P_@!hq7ysJ;YYy|hx$zjOT>FqPi$s3VVY3OzEorm^=a5J zFWZA}UHg2jL#|-nA@zl{JRD3r02Sun>`VWpRTn}RH1_QPbT5j}DE@`n7EC3HxKHQO z{-p>Ep%(JT(Ue0NbkIOtg5g?=Bs&aJc`uLYi?6+qTPdtH1Ok;=xb}*gVl6kscND>r zI@)4jMT^CV0X%TKb+2+b3KAmdhsHR+nM&?X7!}6phM!++nG)am+c) zJAW-xmfcah9ced^PTFnjpc|Nxf;1C?K^1O8Ed}q39h>9$Gg`0|_m+nESB@+kE`xMm zYx~kEW)OkN8S$wB<(^hr%)R7pvC%JVF9VTjKUp7ykCs9RFVJi}nxTF&R=fhTA{ta;mT7%zVL)vW8~^y&(b++7kDf#fSbCet(N%{t5-9k&nL+4=7J;9o6T{nyp?_x} zXWTmGl7ZDA6F`a1YHHQ{6;E+cVpDy1i>LewzhOu8fmdydFxmNR3dfBVlVN;E5Qvre z1C zYKiqAfHh>wlwd6O_#!i0EG89?c@_~xk^zPgMz&g+@2OxIz?`$03GO|j_6R*U+F7#} zcGMuQP8)q!rJXD^V9dkv2P|12)1pC zCI^_S1-mD2lr4D+tqnw;LpT(t6)&{DU1yUREx7NYxGN{JndR8uDE*Kg$uR4tuihAz zeyhDj4a0^7jQ}2m0h+gCQ8o6SpslKuHUVfa#i6uy>Z}#ZftzroUH{VY6O#kg^uil63aE zqRzR1X-0zBhDh_cNVCK!L9#=av?uh+V2z!eA*M%-iSagLLbSH)+pN;uw)o}8$a01&`m@D&g(*R zlqAC6ntxsIjrQ0v2?y`M!$9|K+K;lrheA>&e??J&sB1gohuz0(y%fVXHunn4Oq#zh zMZMq+M*#E&?k&7ePL?5w228xIL`3pa7sc`_6vjGHu4Sqg9k{kEKMSq0$SzCY{=Yd= z?n)Z*LB_??^R7|01@7A)Kyeq$R2mU91gAzYCN!DC!q&Y6PKUgfcqr{0;e%-W zp6haAr(v=)!NJKlx%ZMD-{|T}^(QZWh~E?Q(hsf|3?!-Vi^UUW){0aYu4((b)J`pt zWU~ktugsIujaMQt4_jE#5FM5+)p#SFQZT~45_-Q$4%Kbh;h?>NXjEwLMqWjuDG4(6 z{-JBtNB{9(EckA)1(*2(yK<+Nta3C#(joek=0zH>HuplHOGV>WMRxvZC@|0p*}Qla zMnZKips#b*5QXF*0}s+O3i^{GyRx;ds;pqf^pwg_?f76E8?)aJak)$CEXZ#h&M0g4 zgWJXDlcRxF3=7*ND4Xqi^+m~ zJn$L3fvQ_L(uSY&3j}J!wxacbiyiKS|c^bxXB%=b&fBkApHkO5Z@TrV15KUP*@Ci8<5LhZ*~aBC*c7wg5l zE)1I+)|qxR%Ef~*3{%0Rf{^52pM2k13EfzXZ*E{(fjo~<+UN&0R5bjGJo2SJc<2oe z-8%cSaBLRdOmM%DucSt(HUDvOb;1J;X_2+MvRo6Qc1i-B;Y1jt3vYbVV*Svl5BP-i z7HB2Jlpw0{>EBHL$YvXJI$0+ggSwxB^GZ@g^^uN8XOF)-mK^SaduRP2Gp)>y0Pe2m zc0u=eV~*a`a6zc!^~;H4`~l?^zP)lx?0YWpc@pCk;%o-qFCL&U0!00O)V$4KIIyOAm@*EuGVB9eoamDBq{-3}0!Z8%)0u9%HJCVOHOL z@=;bTD;LN9I3YTx%O9F(RY4D#ef!BERLKMU)~5dC*@r6NY9HW+*0peOvwysj@sKR6 zn^WaYB>J0W$vW8*Qk$XtNS+aP+R(F7{BGhnfI`=SxGgfK4)|q7vMZ3%n)X-;+E8J6E1rphkg#T%#TCF15jFl;+iAz4`3yTHwU<4zA+J;U~6@!06|; z3R%4rUS)&up&7DU1gcx4MDv$gbpkBL{-vWlt3Iqn%Ycc|2(^NPC08_$?rk*nARZgN z<@sABFmEqZA7>5^Q6emX>Vu~pX1$>8E=$W+U-8!SH7oJBFixBulY!%^<>SW3$@zTL zekV-R-c}s!z`k!G|Hfmi2nZXF{Pkr^R-#pQw37s~^Ygjyn)F$(zh#>^u$-d7!)E8d zVUs0N$1ZyuP!KU4;o$KzjWM=5$XGA|OaXJ6BR`iqkc?V{8!W8#A|xc|MoU0I#T-U0 zn2TYHevvdFhR?%FnEq8ONXXcUAmxdC7}{4FJBNleK=zBx1oPT^&>)~p>NJ=$A5D#6 zmJLA#ZS{>;=cXnsL_Jsqoy2pS;Ey%-5q;A|y&^>g85|msY?6J~{D*w#fBilM2x87{ z3R=NqE`Vz_`7v*ourh#9DbKRv#36HK1AUMRN~v-RlfPI1rP$ORhFzuHtd6R6G3e{) zB@#7okbm~;;e8*Pv_v@{5-lFOEXRz9KI|4pyMPd6jJf+bfk7gLpX5$r7HUBIiMZXG z%VccO3Fk3x#Oy_VUNOjnM@b1Ai1JW!V3@n6_mRCLu$L>hKgHk$=as+zMed2bzuUfi;(Zb)v0szQ-au4aRbIpNb#~2{tTQX-y&ZkB%gJ%1 z?C+0m7v${|CAx-ePRY4$SkWEKYBhZOq5Hu^f*coUnZBF;3^Z#{ z562iA=nMjdA0qbVzk+N77xgW@9nrrtG$o_Ow1;B{wej zWdsqIdMGDJH5(t&65i;}%3b{6@K4?4jhJ!3gEdY&{oh}mkvem)$-hlFBAON58BkBu zN8A=ZBK_BUq^d$5N)0L5%fC40(nq~8nkLM8sj& zIy_U*ON~cq{NI-n>v8ctTNSveC`` zh!WHzut-To!nL&@;wqnlQEwL&MqE@o34biBH^^@IcZhQ5vUwwWBcQ@QzfQGu$*=+e zf3A|!JPk@ylW6XZJX#u)rRt?W%+t`Qx6civ%1J}f>dOWP-Z>a&T-J><;M`gtO#0epiMP;TxnA^|t_b%C;j4x{F zP=4MEpWJDyUFO6SaXHtM{c`NcW(V;f;=mI7&L_{+X&*kGnUP5gN$8nQ)ufkD+}?2i zFsi=}qY=3xDkl~mt3G4(V$u;T8~u+R&e%1i(Yj)%EaW~yr{e$A>le;)H6SVH59elq zW|&CHF%3O$DYpozUqE_><4;Y*k2h#El1jG}n@sdGQiiuSyL!X>N#oCW1q1lmc;CPr zxSXTsruGb2rpxs4-}zU~4%-B}jt=f&Z&Ksz2=;H|?-yc5&mGIFplFnbQo?f5Tc7ye z0)7&NK0J~@b`E|K*oegiP*+SU7xu^oX8Z3?QV4}6(-LdSVW*JES`beclg$d z(cz0M_IE!syaYiBoPM$MmjOe!>Vn9+HeX$Wm&}~`8CvGYO;`oQXP)$-a zjq?>5>^DK$T7FLaXT?U6&kqDPR074x(PW<xr5Q!*UWnFY)NHK_7><6&6Etxs2N z>{}x?fu#p=p64liWjVJYHc)$PgIzjQtD|TB$oF8G*74F|@L$)tx~?OARNZ$PMoMkg zzIgV`S+jlDeJ!M}-j6wY;S%}O?bXkCVw%C%PgpI4`*+3!Vk8G$$cNV%ZnN9yCj2?s zTKyoyP?hRNLIF@A-Js1VB82E6EKYj7`+_f${4qlvPHhZ)0!fLSK<7zoOOMe@`&$@2dXfJi z`>%Jc@6E^W#-`lsr55J-es#zlZzyT6TrS%C|Iz)^_Mb)rEri^Z+w#FO2<)>!%~o+; zmH7$1dZ<8_FtGC2q)xt3*2=zpR`W~aMJzuxVbvGkt!(sH|Hem9F)A54^5fQm8fU!eq-eA3T_q!EAyR(P^s1CCR&r)_)j< zRMF+?P}OA>U1ffGaxy&iOmX)}v29s?T1f%i=l2}f1KrV&cowCzH&8KF?2f&}KX{Ke ze5UKL!TZJSv)J04%pV9>Ppn$~Bvk0}swHEN!;l`hO_v<49)qMAwI1#Qce0ib8if+0 zGYoK8pWY1g@br$1t&%QsgeY?Y$L9~SI6=gUb3*PzG5SnMg z&%_EL7t%*FghmFC1FAOdWa-H?pm6|G$`--yiNIEyZO4Fes`a}(sz-y~7*Fz0e~kRw@^3-L;KK zwrJQfySin5p<&!Ab)(R9{+c)jbwC}KU$s_XpM z3CAEs^~o$>ZMP6R9q5x!lnq5lW65>8PF-mGKVtX-d6dg*Hj=YG(HeZ;id)j}X~Oe; zQX(dC(EUx5`yikL)Z|p@DLXcVi!K=Sw(@l3$zFOOo;M0-)b~|;<;$Ns@NI%0Rv{Glh;9brMNoZ4L(dDR_kE~p zeqhKTWte)0lZ`1K#Dc}+zX=RJ9<&PQo^=J+xEeDE``#k}=Lagg>A4Y?4-L+%Qjc=i zJ>eleh{5`x3b&+n)5j-;=_y`eq%U}r;!L~S;IbcgUa=C3CM?FLTVXl$O*p9XOU2@o zm%}Y@T}jFknUt+f@^0*JESd~OWpZM0k#DZfQc#|S@{tv*!+sc9Ug{JF(KSX6CU6YT znM5eDF(d&u`(dHmun#t<#FM)CPuBSAAUcGLuxPOBLZ}Nq^tio4%=zB5Q)kF^O{P4% zb*dvk7R0A}BBi|e@g#g&f>Uz4mj^!A+E1R9Vr7QApzn*ZywtVq&MoxZIOtsg8g^L( z=aBq|SBkgUiRc~G@PY=ZT|)8;p#FFroT++(-2t#5&(@crPdR4bjZcTjDw;E_F$#2z z_e@#@lo|F#3lYopIq2zP;fAwo?btomQ?Zy|#dF@hb2sDFcF*o#X>I=8;k7MPqoWxp z9f4L>8iUA9eaXZgyV=pDR%&u8lpX#}PVem)R+;4S$Yff@TYoygyx&-+1#uP zd<5`mnYi1SIEyZr1eDcZJ(trnfMXQDb~6{8f6$>rkQlV;w9W{apODN6$g+Qst)YJp zo2QaI_>q&q2iQWrHg> zfkUBT`pt&1RHMvpImB05ZAL}k_! zm*Y$93-;4Ay`(F<{$XCzY_OJLL|2~36!RU|Y$fM)0+(Yn;XjZ6!tZ{dKT{;iXVkoA z1Jni_2wEixJ<9N96tR(ix^T|_Pqqygm~B-UEN0Znr4rcty{P${r_+R?6PWV}jnfY( zZWG!zJ_rq4AbtV|nPOm4PzPF92ly*kn>?44R4ruA=7fGqbXQctf~YHQZ&8v>i?e#r zxr!jbY1Ekn7cR8i`Kq2tb0Q>m>f0WLv?>Vw`~8DVny8;l{I|5)pfXv)q`)p#6*Fe9 z$Z<#IGxCci{mlH_qWgWotP$q@e{QB1BK7;op86IP2+yO`6)mn-+nH69cFm#~x%{4| zfwn7-cH8VMN{V zJSpPT8E88+r~Ag1e!SyaUSoTJlZb{JF9VgeCZ)SOG*hzJ0alJ1g*b~e`Z=hyhaYfA z{>fjh7)xm6DB5XGmZ(ne6_ar7K#k9|Qb-h!x3jB73X?O~V$__$tZ^N+S#xen*qwIf zH>DTqzdr_?QZy!2f99-5J&oo--AJgbJX+)|O-%Z5H~NhJ{(7_>aeE>N!h+VS8f5fH zV?XBT4K4mX?v&Id)4|XK>!k2tvpEq=7A4fXLs`WZKL~8--wr|+WNm*A!~*pVz_la=7h{cI}o{M z>nK2+VUCS;NT|SSNy=b~o<_M__Pp@5c$@XI9R<+WR~0N)ts+TIG&!c@F0D-By!&s~ zu8A{5dQRWngm(c?Vv!KM279F;5M{}REB(2AQ%=`(CoIauUDgb0uR&mDzOhIUlLwLACJf&vA9_It$=1Z;M? zx|at8gC})4Wv|Gr0C*w_;h_3KR~Y1+VQ@+vrrX8VrrK>1RLv+%hTXI33sAhD@4eZBAAA>1yIv=263jdv#^jdrfxdIfa6klNBI@dOLFNVo zLR>Hgl6SqfWV1|y;;RzAt}peEJmH)D59#RqNH?md@`YEEb~CC^GO);VU#t`7&AVW2h<#B*gZ>RkhrF^z;7&_OKTF z(S;^zl#4dj5(vTisj&V1_~k?oEWynVP?_CS{Hl>sgX&o{3n&XmTg3R`^cy@|2@Bvr zrU$8jYxEP+&N}<{NgjoL#+gW05!pt)wE@aWV-Z<=iR&zV;0GVRINS{+!E|Q`&am?* zGyDMktn+0+!qN!gWKk5MQgj3jCE!LwtU#{ho+hrfT}k~}xWBToJg5FPtLcCAgiXUB z-ifrk>q&vYU<^1bp5Rz+>1Jo@pp#rUUAb}sU3!K`prxqvqk7Z8w%;thvNP?8&mVTF z^@@DF@UVl7ds~SoSQBZvKO*Pse!1*ERlCod{^w~G^a*9c#SR|Ar+=gcbhlcMR>(+OZJ zKNKABU9>#k{{=j0F0}TP9(-$~4Z1GNqi4q@|2yw`Y;V!{*2?z=A06tI$9l|_hKdv9 z${z*Ti}%{6XD=?D%=j+^m^>S^p??f9BXUk0;8%Xz3_?OTqRhUC22eZZii6YD@4VEo z`fP6{YE?kQ!zFcxgWjabp%Q}=P=1FOvjqrexp|@k7VSrdqK=AB0?S1%xA3V3-81Z| z`51Y6B*Bh>pFZQwVXCa+|5IOqjL=oEPk@Kp*ow2;{a*)M#W3MsXfbv4WB@H1C8%Al z9O$;+-vw`giYiP*3URc)u7siWC(&r-G?W-qQ+fnba^qZ(C58bRCJcuT|Ji47jEQd! zaYy(&Z0#GeG6n1R#;30knq?|0xb!S|UV7+1SJzlRTxLpf-y7?tv2kDR%yoH(ha)@w zGJb9dMlPrHF+OSMD4QR*4!#8W-Gwr+aB1SEVbF_3yW}$ee2J>; zth4<)bNjUP1aNTNC2c}baHeW%`_K}vrTNtqq9HM=V7KLc9;qgQHaBC+HnlU{A1b&~ zD?e;;6Z?C$|1w7LNXCJ`*P<^IeIQ8lNo@8YXYJ zpzk6pFO0HJ9BBM5M~5vyXy~5Zyz<;!{J|qX$B>967FY8T)2<4`^+f?g5)Vi2W1w)m zk~TnZS)}W;G=Bc|OVj4qQ@l-f)hM5*=DXoBS>qbmJ&|hPm9E|W&jk^TIM_cfVGYJO zwIO}{QbaAyGxu-*`5*|vK8W|?)blc_Tex{xCsi4UP>tkY+NcQVCuIFj!|M~SEXbWn z`}2(BHbkW2wY7C5#Op@`21ZX9$B6)}7j8Y&=K^6&$}1WWmq3X{M!#{D z!;tlXj1dqSfPhdGz{Yo4sHaBa)~YTIPnCr2i9k6F`2|b*d?A?V-}xuC z$rNvhHm_C32Z@2Eep)T6(cDmR;#(cskB#Tg{G$L#qDPH}AcRIAYG=lP&TJ%J=4AA5 zb1XNn-uKs)8!;PHO~`y-h7_(YqJ<2`?r^|z&~UwY?Eja8`~rRXy8g*Qp%r1DVaab+ z5lfqQE~>1^h1@mlN+4LjjbFnZf$89A9@`j&h8`mbQDnI?+GMrq5p^?*ve>!gI|>?c z7w6Kuhs@nyz!L)N4I5ZJ)jOdODo4-@r z&#J)4qXe#9`Wvke>1knhcz3UQ0kkO1vqSeZ8q`)*>b0pR-g&!UAM+748Y+-+80HVl zGl*7J-9dT}<4iwhnCSM@ZDM6Y4f1v%cy*1;he+80F=2(Mox~`62-cp}%mHd@qvFxq zkC7~yIP|L2kRc3Bkt|VVvtH;8-HUXN8QYQUUkh|9Th*0gQV-38_3QOI=_^tS$GC9kF9Q3jv6D?j2^zmB~`M(qF!qbcG8y!5Bv zw%DJ5`OVkoSUf#tSZpH2cd$*PTiI4DHSX_wmtl*Sr zZ;AAL2ySt_e-GU_UoHm%Uc;!Gi+IkFlNzRzedMr>K8HhZnDw@LF*j}MKO)73egaO%c zbZE}ZFQ9_-Bi@nvO$tqCl-#sUVi-LUw1Sg4a0gTw&+v|H89M*Gb1O;#b_gh;EoO^4 z<$?=O9v_|%+Roho>Wo-!3!bT<6s+V*-TKqGyP#>ruR^Kc>IcIK%u}kh_f5R#@l`ML zSuLr8(-+kd8PAX47o@vLRAIvhAP^t9ZEEYIzVqwYJgcrauJ^Qm9Vl9{q) zaBOY~aujjety!aUE%GP?3(kg^=M+Z1RWf4VQP{w|E5)tZV@WGvaB(NT0xGl8uP^C? zyUy9lc$-G;oS`S%sTK0vX9jOY<6U;hvvkG?(TjxL_+P4j!|8=Lb<@a0_$Jcs!z6Y4D`as@hXB% zy|KgEWu2P5p*YxhJ)*Vx5~u{?b4E`S_ic ztAPaHIueZem5RZb|7u#AT*k>DU$yg}Xma`J| z!f~_aGT8iaNcR&;^&oEj84oQtH_H{qR79=(Kv8iB+8rR(pywn>6byytOtswgW%3g% zDFdHa00olCuXkM&>NCO=JLl;apmuNS@<2t4O1Ah1UIm#$c4!x6tH9!pAl;VWBNj>C zKmIo+LJZjO@9+1*_D>D3DKp7DcpP5~02>HK!piIO1ad*~IWu%fUwv_d_RY8_V8VvE z+z3=C?ZH+%29JMMyLs!J5W68v{BMv%vS)Oi5#=QRbePjpHOiQkzA4pCXmjdCohZ4q zh|<(K^%&JBH*tGv#o=cYubg=`soe+g1`Z2A1RW2B^dH?}4xbx|=2;NwBfH}AbSs3o zsM~kXKB}zvrh~XrC-p%XCc~ui2(85F?@>J@E`yU29(%zv53pEcxxRxJydj|7bD0qm zXhLRo2jfuEY_~7qKdOzvjBGP#Cp*~#HsuT{FC1~&=Id_)3Hi!*5~5HI=G&pXK!*h( z9V=S}(`G#P#zdu9<^~bXgb{p0Hy3w#LNlVXzD8am-GxHSCr{eE#4er!`)!%y$k`xM0ugxhas|2_kaBcD)x_5vP_kxQG7ipva(k)DzE9d-72s)Ss~ zxGt?`&M?vAkMyQ2JD!aUC%$^hi26sKsze8*mH#3*%w@p)Qt2COa)k?N-KcYZqoWp%_8Y6>w{8sXBWos81 z0&_mM1;NVTL~Fn+t9avfXxfVedHC-Lftzu(GuW*v;u|tXloldiFGTyd4ZgnU8onJ2 zq_L?4XRuZYnSXcjlRE-Nc%<$KY{f%o$Qr%SmqHD}MMsKvpJL|BnL3N=&mkp=X;P7=$A=ylOL935e_;+}+a#`WMm zA+sx^If4r`{Kv%;7c(bE`2Iw$}T`(feg4l}6zq{kn zsUqAGuz9R<3X=ELYkRx%t9r#_>F)TkL0uvCo8EhnbTh~5>qMmydY(L}9F{?O1?p$& z19yq3zL=moY9_W93>UNPei-F=aJ(E1SDXAug&Bx+s+3#f5u7xcd`=dye)fu;Q5{*v+fr&cw> zZ9Dwaq?@7&GIMSF$#Tlti;w7OwR;n6I3*{(gm)X0y`rA2_^%85nzU*>I!8GzqwR{h zxE7#^u|uMehd_>4N>mpWnGCl8zJ?sQ4tU2r+-|3^nadxKXU*tDv)Z$%Iv6MfMy$y9!%njkyDJY)|yPo(sh z+o?A7dzlMHH$!G^a7Dy`P3XjfYGP9ms7^_*j;QI2F`RhoS&MUtE@3bu**Nru9O0ht zTb+VBUUfdNgX)H?EIV>Mf;3D8g5JRI=YrQdtkk6>xivV3g6p`K57gTN`wVdyfq7m?;R4DAQ_7Lg&4g`=%sr%f#PwZz@{S&yY& zd;+>VH{x$;*h*$+@&%8sZ#U1i>d9GU!`{$Fl*ECJrEvtB*eWN>^fB<;) zY_Sh*-NvXUVRmN0qCH3W$o3scqX08Q;{&|_8h)aHK)#B5tt}$fi~Iy!zu&GepVoCG zQmFtkmj)B~Gnl@Fp{cun2Ut-KA=B&KJ2*^EAfWH!FH7i8xSGF2Ic%ELuUS^`f@x+M z&Y2koD}+0zEO%ThryzJUC&zJ6!X zE=9gv>oN#%_$_x5v1QhXic^+PNvuY-%!G|jQ2Z(K<;hT{RoAJ^KW}#@fI>SBub7up z>__wCZ4uEv1qKgJ)<4(dAqMo~y}jM3=h#gP3cBa!#?FZFvJ0B7S%!^Q#W>>XcPiw; z$rU)8uV6!uOfI1C_EOEdC0f^T?Os=(m%}>F;Y?N=Omr^Tm6vPueWWG_3W*0n4QdS3 za7*zVw`*nS-XcY!K*xy1Esk%~+r62~wQtWFTD&{0b+)<84lTPj5BsX6E@Xk=g6ghU z>gKGQif6cDBOm-TYr`@>?@)%y)Wb%u5H?>(v3 zh;M(m=be)eEIyZz&trWaU6_LIIdhiNgBMTj#F)yN6;{)} zPXP`=LKi4;43xpb-KriLdncmi3yE0!=1~=17SD z5G`V2nv02~BYb&Pb~= zYVz{)a!^>1hv6wNeW$)B6St-F5s5D$Q2QhjM^7VyT}{*|i-8Nmr?e_E^%<>Cx_u3T zTdriNA@UF)igY9jwi>7S@BaGv*bwHq0U&)!F-Rt(KGJD;-h0%y4-s)c5DDw0=0o`2 z9BxdG+hOC-@T9?-75$6+y_3)2Jl`KWhe@%XcqD-WRyJZ7EaW9F*)dX)SHK@MLNMbg zGXsgjSc!x!f$e}>+?;cyc>a5OP@?T=*K3!^s5kr+9F%1SXT@0-Ok?WiMw_Y;$Rp}l zLX-^Pg*7XCh#;5{zm71LG88r1I`F=>vyvKt_PdBb6k zK|rSFD(aQSXgnqx=yd`F0a2Kwi}&{%IQ{%4Y3-b?dDq{YB-OX{_90d~7+>}wtxHHk zA=yyw^ix?-6pak=?=Uo(^DC)rb(sx!HR9%#!J7fC8)Y_{jQO8v-_n)C4_7l2QQJUZ zOj|Ot2}|W!^^IA{KoB0|16UBqRqLsy+C`;xxxHjB{X+iHPz@+IX3+Kv^EGL-61%QS7}-TW9YxJ>6x0fY3u;OhcQ@{Yz6ke&qeNjhg_v5P>Y}coo5e-%&4ekEjEUuo%V-CZiICMpQTeLJ|2X!q7vEbC^ zqZ`IdaC9yq@P}d=ih4{pTJMRI*7A|dvjFy+FgC!T28umr8Sbp-YRt>UX9 z)?Ls8WL-Vl5KYH0&zY7o0V9|v`j?jR&!wWiACqxoUvq>071BBf|0A0H`}{%sW&%fJ zoC6L5fB&D5Qcmp0uP`9$0qxFPm9HA=QzH0y4eF5yppYqbn)K6fX`=9nQVLZ|A9EX0 zqT(iae`7a;nM1jXWPxA&d zWwzR%KHw($MZNx|KYefc>%a3)yZeD)+B)Z1ym|ZfR|3TUlKYs55d7V_9K@T(D~>LI zy13;a3H0}dhO8YHP4_}?9&{nQ^Zy!;B>T|5_;m|Hc^-0WOj_t2zF9~};8ody2KrF= z_Q3)`8-9N)sgF0BF&JJG>6*ys-8F2x4CroWt+UKttJv}I(f%014u&YyO2co%^d6OR zoq0JZUwGgIh*iFb;0?|)y}VhhuCA}||B~<@V;C(!{6Z22;R-JYTP3fe5^r*R|22dQ z(fa2_kLU7~&TfKnt1gILfcsa&_o=sX!`FQd?bTvb!1^VSWhRkf8tB^5>R*2Z6*?r z{y`YC<7TM&^6)M@En;;ByON%k3hFx%jbdE#5O+uwK1%6%p#PhjQ8Hq1P}SV+8THcC zk8|%}`YG&2fC-iaLyK@i6tEBx@^8fnL>RAMVik9(43Qwbla`p@h9?Q6%77O_!7MIh zr_4?R`(!L2SIbZ*%ZU{Q!3DGMv3+90gZ0Ru|oG zDe_-P_-)~T*FX6&C{77|htLfoZE^@80s|VsIztmN!bUE##eswPD191(fyI%bN=me6 zW;>p`r(z7Ca{;bAaQDvgh|IKu0jBxlFITiJ9sqS{Lcc93dR}J4{Y?)Qi~C#Q=M}Kt zu0mdnnsBJ{U?=V+kg88WDo!7<3n-sG9QCK-Rt2xYKiURRM)j`xhtbPN$y=+NN1pUO zP5;aLKPpErhA$k@ZBQONBC*BH23r>)I0x;pGivhyCbV4?=UCTIC$|U^frj|zOh8oe zl0#V`JVhNoBmp&O7QsXEj2VyY9m|{f9UZ1+;Ubgf_1>b6gr@N2!|(3CA-f_=uLrz} z0^zc3B4ze_^IudR@Fl1pXW90?n<%SU?*Aa2$j#eXh6@1Iam!_-8gfK*_!t%NSx9oS zr>vJx+u`Bf^=>YTnB4z6_Nbf21{^T!ellM6QKG#M=&9`Rd(HiQrrsDpgyE}u?&xBE ze=F~<(mTfPnq6nQG4of;{1DO_+WSVSs2BoTlPh3Q6$m<~8$oimscSxcf;%{0?_+CNP%sD-oO)b9dM|F9FSb$UW!ZP}6 zytJlM$LHak3>DwM**2g}$-*B-8ZTb==BkyTMY(q@p&f1!6C+thPOM^KoQgCGoufr+ zL-%dTp;iemppOJ+3?leR~YPGYz{c>#Hu$2r~yzMqE5DJ4Jyoo$D)2&I;hTrg*yO zA903Fd-j>yu?!D6)ss~gbxfEWf&}STwT_Z5->ugYSvHbY^nFVpLy$7B%@7 z1m3jSB$e8&n>fG(qOLj?wB0&wzVFc?gfv`Nc;ZvcZb#`kb`Lbt6RXb#a|x>lGA=FQ99YU@wF@*~P*%U+92a^wFRU7`6F5J@@;ScA3>+?nbE_ zW(SAz{`R4)yz(!?`%j`~&?Zz>bWpaM4)wfOH;cfZ<3i+%ty81UTf??i2KKt@d?Wsyu8n^D_4>dSY)T7-a!3!QG=xwqxW*efA zxZz58v>-#OV7fLZ9_s7?fe6;VSjcy&GMjDl@H z>G5i33Y_Bj^tp>THwBV)R5M>7frr+6z_!7;###-MU&vSfOUf7oJJvcoY21La`)8G_ zK^=wX%ScM@uI7c1iyK?s83dbuv}1wzBqg9ruYumneGo$n&>bR%x9%vKVSr z^+ovkfw#OG>yHNi!r|XK-9m)eN-NDoZqC}H0A&6b#RLRq9TQ(C=eO~nUhb|BR6V|u zD?W3zPXSVBORars@iZ(}4e&8VGl#L#mn!*!GGpT+%{K?IP;NRUdo$H@%{3ApHJ?c4 zW#M{s(lm8d{93YSyrll3L!dAyRB;qKv0JV(VcAhj!qG|$14@9mH5nmGg6@MkMPM8D zhprm}8UHs9uQ7Xzso#PKk#nT%tf+fFzpZJR1^39KOA*I)#bpErVX}S88=g_ga(J@i)6e#iTgbR^^>VGL(HB>RHum|BgX7w?5VOsg!B0jkt@#Pe(kJ9Ubd7Lk0 zLO!4wXrg_&Nc)7R#hsiLIiq5R`1bmp&Z#K)Vh&Tijb5g1ueL*;OR?R$8}NN?iawFdu2x zm_7C5X3xo*-uJm{A5~Q)i0TUuiyg^HId7(%qSiMT~#N+-#Q zv&z~O03qYelEG>6f{`!?J!lX9pOF}Y6d$#?LjIVAunI~%2vEPee2&d|ndhfF4V>WC z7O)~A$q+@|lFlmo(G%EeggA1|BNT|=O7;#$-AvOnWm&gzZP_(o&fpK_YERGRynvOT zP)%rDJAMpz^6>Phrrq1D`#T)L}dmbF|p)ZY!&)_h3%2mv2B zY)13|=Hmj>nC3;m|(DbbrXP-ZPyw&{V)wN z0EVvqStgmS+CbHZIh!kWic}42tELo2Yl+CK7CnmTq+cieS^7t7r_NKzn$Zx+^3~a}X~gzgXJP!sxCm>#iD) zZ^Vv^zkoJp%~T|MY{rATi3W0KKAr|zlK0M}Bk6kPR!;v~BvWR8d>7#c;F=djf(Q%3 zY3}#nFynp1d#bm(cd4L)#6_cu<%dW~Q`0_uV8;*s?(87chJUV&(raAJBcG_d^u&>(%(RQ5p73G*VCz>5UK)JXNMQ$x~m< z91^@sQg2%*U8-p7i}(k`o~(q8-0E|~g^w6I`0_IbSRRE{3R$A=gzapYr#h!R`_7-&Z+Zc{6Am~%21NTU!y;(1EH^zVpYGo2O<7ww`x)Dq7E!f zxaN!a7mX|oaoX)Z&;CG$&)GnF_VQd?G2`LVPbiuIMx|h9$UbrXQvc|SllpY=SO#_{2qScy+;_%7+?Xs|(+D*uO~U9JEe`HO`M z9|lG}pe%wP&z)F~Y!+B!*P2K}i8_u!SPY(@Op}n^ygxWn?=6?K2R*X(VUEppv?_2P z*kTv2Mf>A)-T_Y*3wD>h8Kp<*^W7I=-s*_YV6TXN(?Ngd@{(0yIegHhm$DWAdGo13 z-iur!l^8edRB?XVt;SQ9{oA5Lw(V?aAUYeccXd+lxHMGa!I}!Hj{(#wN#@AH`-{MC z1qzD*I6`RP`yPSW&{t8t_lQfzo@pP{tT;F27D$BY@{C0`V* z3%kvCx7JW+6fPhvKM7JD6I0G4|rtpQ6|p&eZ;cm@evD0~O%cc|g>Gj!5#!3)U*KbiCsud1J`q zg@x`U^P&7ZDUUG9Uh#nn)~YUwhmhRP_fIU}ustRjub1LD;!;U-kapl3=X(GzdWu(t z<#FS<`gzEDOk7CzKwp*NW0_G5G@vhUuT`muW7Pq4bCxJLXTE7P{5VtHeP};)vk?5D7qVo!90^t&fy#3 z1k0csL%@Q4<6o*bwIy$odn z->6U=q{N&4Am$AMYX0uV7}<8ZT%B%eX|WJvXP+*o38 z(nN}f5A7kRJP3@W<>U?A(EB37p|W6%m>|n-^gSdqywFH8QDT%_SAs`##ZQU3B~+L_ ziZ&1vW*Yj#+q6jZ8bZZa&ra6Y>-sl~AU>;Z6@_nd>=B@&gQoq?28?SsC1Cg!{F?ph z&rZk|`TRiG(@3$p2%62$wd-QjC-}9F&#|fV1t>&uNuJ^!O(S5z^OG802P%chiKA%^ySDcTS4kAr2lQ$D7^4#5IH^mJ#Vsu~v;v_<}ej zXTN`k1MwTF(&`lTWcQX%^o!tizw`uPxj^}xd;XVaQ`EOom@CM34=@tohoY|U3%uV1F=b()dv6Ak_KYFZ1PrWSI7K&pEY^O8 zy!iXK2+!Eue?grm{({?>cBK2Cms)=pN$8*EZW^ZP@L>%LEq$*RT{D3EA&;i7zi#`9 z)1>dHw?mk%=0{=74FrMETO?g}^Q^CiDw`7_Hbn^U&g0|yu-)egMZOy+V+Nor4Q~5d zCqK=ZXAkkX#=ro&eRK+UWfBmbtf(a z-w@I}5KZRoR+Y-2%>JDSD5f-5957)-Z*fddhGLeYO}cg*NEWEG-M-ykZe^85qxkm8 zAke|yO>l;Y zaC>~De1S>p41L#$ptaibyTPDR zEk?f9>N(l#%~muybVe_B5xB{`?j=z*bUq+I$06;oY_J(pDCtDy=dL=oCo1Y34h%8d z=1BGbRQdg1H+G!)Eb@;Mndt5vJMM-P5MsOiCqE7vqio6Zl@uQCM-sc;ku*hxZ`wZQ z&PJW5MPx(q`Cj$o$t`a-{jZDVd^@*m@!$z@ z4tt}t+?tDFtChk^ci5KU=EfgPzi{JFM6a)fiW(iy7jb=Nh5fmOBP|A785I ztV1!+5jF2NNe%?ZSEuZLXqRF)<`g$u&ykSe7Ny9`o<-hNf8gL=loRq z(e911?ITSDo@$y)Aq#am1z5?_SHT9Y6gpXD53HsTL;{o(@eZOf?+BwdGM|&1)u{xE z5a?Y3j-R?PNC)G~sh`u&q$7!0Gow_dq$&Pk*PX{}x?0&dX|-f!Tn8n{SPa8_eNPw{ zrvxoy5+dY^`}VD3aj1xAzqIORIZNN4c`y>H6?WXNv_){3|NM~WZoQ;k1vgTl+1&P9 zzY1=C2bi2SQkXS-NF}e%kFEXbh&!Ty3azw5=>=8=r%RF}Md%QfY`-(bAxvr@k&p! zX^uzw7%CsUj~Wl69Beogv5DAYhH>vY2)nUGc*-6yV&>2=lMQRt(syEOJbaX91$3;`#*v7-8R)t;X_-vbV+kESb-oB>#*xz`9ZOScu-GD~#a9gHL>#inn za$b#w{9Ls=^5~YlQEq7PO?0#0KE=uS&YTIt<k}mxgEo$YbR@G%@T;>-NH1?+x(A35{#VtFLGA{#*bxlr)k3_oG(BM3pfQ=#Rz=6iKA&JS-x&6xdyWm`U=WbK#Kh15ohSSssXhdL4Hor7j65%LJMeex z0RAO?=;TRt#k4WkD7&*9v!&_sVxU_HTS{s%s5e$SKzL!q#Us$=0Atn;`3EAJf zQdyGbd1hOs^!mm4JgXU=@;<$avDun?699?H8+bO+pX^5#OB~V83!U=x#J58iHQ6v zeIV9?W*dy9c+A;!c`)jlrPZ4E6_juA2x~YsVbI-JekCY3;-6BVJ33t%1sbb{b$0B*4 zjl0sa&9yBRt`KwsRW5$nVf9!NsG0YV!B!Bw7GsIg@;wX?tXUzWWOUe+i~N=dY5&l9GaOA1-w`U_s!nklr-#UwGn_0A+LJ`mxt#ytXOw zI6?mUWkuX&W4lePOvL3aWW2$VyCuP`Naf`%k$N6}e)Kk-6X7Q7cl}xrf|DX=>A$2C z%Ts3K8fu3h!*&j#55Bwcgv)jzRUunn&I)au=%(RgVQ%Z#NIYFThQXYzwSk<@U^-4g zi8hd*n>eMg>C%(aYy@P)kcLTv!5Pv)exu|H{c(r%gBEaTe1V+B^ugag{m>h1IQuOM zBAQvO)>!0ED9{vCn^)Bw#2bBMTu@^`rTQS!ny@N8j?I`*Khh{VCii#9`Ps8!S7m(Q zIZNAEBhRY5BHk}m$PKy1z{L~2e{~^MfV}KFdNT$&i?S*}_&$w4(+QH8>j)OZ#q!9VN;kS+G|)QaS3aXvNh+6^;%`Wi>@lI67=0!KN?CzfpfP( zSC2pW>m8$>l4-0FI+8Sy0;Ni~gQy?9Zam{pEXdFLMr3k@@1t0c@?W2YfXdfZQ%Bb> zd1RH{^1l)~+FXRh57ta-^1dA2hE+lgkg)6#AlOo!X(`Mb!uBU9iK@o>7r6Qx|FH0+ z59|Ym@Ew!u=kY)-My@^LHELduUoJfxj2icbUQs}Jc#i2-%Fprqe1S*FiR{R-iwFkf z?KTD;88qp)RpB~RF&Y2^SmeM~15e*w;s!M~QG4*(4dPSZlfHzkd>2%E4Q26*aFc24I11_IjqjC{%Y9^p;y* zX_uB!3KURSQ@)vPAZzeosxMWkT*4;qLRw6n7ethGWtL8_S#*#5@Uo0`2R#zKTMM8+ zYaXgzJ;$Ifzrn|&=q+Og4T8~#8MfTVMKI7vdFo<)?Ae&oc;9(3-P(xM9!?=n6C{W+ zoPEbG%d`Y0=r?Z<&xl!XXhz5vaRn$1i!N8ckaxLLq~i%v!9#)VH^f4}ndq1JvvSNj z`p0u-TFTwxPo>855G)zxW7yj@>RFlJ+)mu}Uh`35NIPHO1!mDgQ^Krf6@GB?6 zWrDN<6mh@04Xuei2DoV;UQ9u&pgVvHu0b~~%WFLEVC!&GQM$Uw1_52`@dqU*VUs)5 z^nDc{Ik!2K3VCO&TjKJBe+gK9CnMD4H{tUBtr7P#P8w ztU7&MBwxo9^=7gGokw^gj#6swPH%g7ZNMSabg!=J3FxplzK zyxI@~HXo*AKoN|Fo7yi~JZAkxUi7@}w<~Rw_?TwoBb5*h%hCJWEtEwb52JSXa?P*% z;;7FmhavqD#S%q38&Dt(+IPaH4g&b6zGj=_HqZ$pqT?$u65mCf4s^=pA#kTbe7vSLK7r;b) za`~RCGUKPrjPV1!t`pJFz^EO8`+&DtM=;ZdX1|i9?%5UbBz-||ch5x2pF@!_Lgeqe zwfzAQh|B^_g;L6A-Cl9B-^8D<52`vQ)*@(rxW}lx%*QocaT){BtZZhE-C3 zQv()uy!t16SuEG#PP~9Vuv|lABSk@%y7P=AcN2~EUbXwNMk2WVW_bxC*9=7~LO3MZ zegi`L^#_K)3T`LR{|i9_tBWZ2>t94q}TWq!$pm=&rFrM(GF}+%H2l zf~IKEfKOZ|b}{r)6)+pv55Zs{L{*ECF|A;2NhyzNPY=(Uu(g{A7=(PwI`sASAlThU z9DO)0wt#pg5jcRx!dNMzNdLR-45J5+g?u46%Y3Fvncm-dRpb07VgRQzHY!VZ@=GICe{3b0yB&Zgo63t*Fxl4+8az`4wb#q#>G$+ zJ-nH&gaxb66FF-s3`7@vez2fQCz?OQ_DR1`J4$v+=zHAuv}RhElwY}o>>&gi!9T*E zXL35QZ8Y<1`AWwL34ZlJeU}EoH+rgJBs+CkmZ|rhnTKe^N_93}68RpkamEzRar8`mFiM9t<-|7* z^EGfqjB#4aKGuRfKADBy1@>+a(iuHH?O1_83MQbHCOllTG-+P8+vRy@S$hAWveB$n ze)Ek+&P#Ao`#)HoCoKBN8GYQCtPe0ISQSdtl$GK$XC8d_`In0(5UrIb1v(e+Xg}sv zET!8;Pgy!#rm?R1L3Ql=Yu}+Jv$8R)q`cVB1nEL4G&AHf&EU}JvyED*9BxT4fM+-o zA>^1$Uf8fu+3`9FJl~+#!5^x|<}&rKhdqTl2o_mf=p5(Re{5L>x|8Ia2=m8E;OtX0{GJQV&N&zh@8&m%OU7fdD6^;dy#9ME0Pl=b)0Q}W&_n+9^tAL%dF)Sk5r z^hi7#@as1Z*Ioq4QFgsq72<@VGi)uc$d^YDOD$3uV1}IQ8;~?U_OSpE41w2&bNBR$yDY1Fj|PCAUN|~X#nmb z!f+f$^nJyGw3fhAR&LEM#je)t0;)SWP@k{Gm;QuGhe7zZ;-H!idg?T|WBL>eyozP- zzEq#;j$^l}5-}$3_Owp9j#E!I^6y^8!gPEg&^-#edC2l>`fKiVdHfthZ@U}we|Rm) z>?i|z?N$EQIwWv)2l9d=fLo}Y4G6G=@ewjE<^z?It1L+{j}G}+?l}{tW|5h!)4X?& zVuW0=REAtwZDqmo*wbe0SdZhKi;Aw4wz-irv!-2LH17a$QSd?LCxC? z=IyAXDRE)ON9E01U^ew>Mk^;}VT7k3GAz`F9amqp*~cCS%@z>1g7$h&dwW`c-wA%G z&uxM+msn^wU2>DAx3o)8t&MT1t^@-P@>fsJYeA%YQy;zt9PY|EV;ZehS7ZrbpQOK6 z-{FnDNSsg(+_xoZz+7Z|c11={D9j8-Wo`O@8BWmEKvdmY4t?Bl5*{+$)sG_-rU@20 z;F2M%ec!YZth+Ev+VBujqXz!{;PF4aA&^khEl22wX(fWGlCw_?ZU|qDOa*g+7ub}t zo{eK6v(cmHY+tU*J+wt|7LfDOdYi%t5Ir$sn$c9W#tJLurmH+;^^P9~Iq^`)1V9B_ z(6u>1Yx+&W4uOhCDk%l0>j}(7-GJa(K)2r2W&eZ&_wZ=j_$-f>NF`JR<29J5b^r5u z3>&GNbjDu{MD+FyEc*r?w52p`MA(0jUM=^>JQE3;A^4mCdO&;S3#*4FzU&}9=^+^; z_0(|Mp-TZa0*5v2-Wx|Js;~i1yyJOZ*)n}A!oka2`fG3^-g_5F^ zTOL}&`VyB$FPyqRzN=VpwMoW=OQ;op&Dc65sF!&C2CAVU9eZf&n&F5A2l~B6_0b_`_O?&A2ksYT6L~AFds(wK2q%JM;`M2W^FG^(~uDnjBSXZD-z64hD@m@c-V`m@nd$dI z2mdp&X7~9O<25%G<9Ru)v*bQ$a-aLkH{b<;s~yB_IieGwT(WtW->uaz`N-~EbLn1I z*l00#8Df9>9!UWK$W{(^3?5_O zzJj4R0_J|&&dj3(hP;o#;R12(Kc5-OLO@_0!}@ADxg!DAy47TrPC0}LL ztGn=u`sG`{S1f>w8G(;%GPA|c;EDt8H9Mh2pX;mn)6NCX{78e~Zo?pZVmpe9- zb|ib@U(~E!K)~{pTtmqccO)__?foi{D-yAHybsnD>6-u)ziy?yN@oPZ`UBe zGH`1~$}Nz)*}f_(Tia%ON(o`D6);?T!NP<`is!2tXy|EWZw0>?iVlMpNGmY>TA}Iv z?H6e{s!?F6FY=O@y7OD1VJMOwS#p*islYRT;e|rygD#$`=3qFnX}7~~y>e(*z;7)+ z{D%VKc_Fd_5`TQU4<(vdOFU%B_LLG_+(Wvn`o*3*Z`beJV{~e4Urrc6X5ZTHNn>0z z(hWwt?siXldMr!{0irzDe=7zf`% ziC$>=5Q#@nIA3qgDW;ycX#h6pfq^6t$RXf<4*BiA4F#I5i#L9@mI6qTZq@h~cD<|M z)cxZcY82-X_F}Cj8ps+NXcafVV3`;hJG8|UD7hq}qkG;$N4{x4_Oe5{nS!1RJv)qC z?DnKw_El8DfmzQJ$^Kkc0B-VHL{jZizxDY2k!Q0A3oDf<%_c7GU(3sXUp=R)_(9ljBqtwjVdF~AFlV5ZZd3=^H zV>>^}{zbf;Zdc*-WU;1H;M{kQKU-G~PE9dN%86b-T3jhI>T(M0St}W2^J3J^_;N2C zM3!%apS1%~U~N|tT$(1*k3<04#V=Ro(f6(Lc#3oRuT+b~0(ICQ7ZsSCP=zrRGHuIR zY!$g^v2KzUmJb{K3%X7Fnr-nv*;8@Lyjc>npr|+PJ!v-$uscny@9XO4I%FHQl?<)9 zf@9@t`ORYG@UnGZ0@1G$8K>cHGNyg97$e0L09Hxbjb>?2Y0>E9uzE@BExqqCR@rBUM$6GJWuA7o|ah4WF8)RsyC1 z?^A}zvl&1CyEeA*5o^Q%mAUG%voM5H$1hrBj$4yj;Gy`Nvy$NxB2j%L{)N}pwN(wC zozJh%lLu1mp>oRIU#(jD1L&Ta?ih(U5$Ks`A!#ocg_>PKaH|f$%sJ-vL5zK zeY!g9%VQUN%NIvgm+!h+oRYKF0u9P4AUAOs+S5U|C|M>DJS25wnAxSH)HX6<47)=x zToJHoj$r&}?D%A-m0oG!Xt=MaVuIGibe;PPf2xcmAL@Fqg7FG1S7jS$VUPcf>G!6s z5|h^{cuiY7pZM$UU%(mLykm_1wL2fq-8B7H7wC;J!#jvY%H8Mz7$mE6tijEEprToI zjih@QeOi=SRdzuEd>>Cau})f3{gY#uiyHx{+vbt`=8zfImfu6OUca39gvt@rlJxQ& zE92yEvCl?H;XJ3k9ASV%XLaY$^;1xO4@ksSA8G8|8vr4-U&na7H=2Y6YDC!crzTNz zbDlHzRSEx zM%6XWs}fw+JQM_P$Le8bpsCG<#*K(2_#|C72DYAw}F)SIjWRegQ3`lhhTgeT~4xD#h|jouQ`8i<-1$j-xM_-29)6awk4MaWzcG1-#5I#YTo2Zrr#ql2#Yn2JR2FkJ8 zd{enLy;qVK>}D=Jn#C>i>p<8l>I!6pW5;@gV=1#8&T@t4<`OuPLijp^yYMfW|4@-I zO}LWh;iphiWqF_rxGC-3Y3C1=gD;KS;R_Zwvc><~4OKoU2DA>i+FrBrf+bJhoYI0Y zvY<1wA0LR4#a55$F`e} z!oP*j34LJ8T~sLBIL@oQND0|Z1PWE<+?oamaMO|7K!@ztr?*|b1?J2DSUMG~GPF1x zdD(G!R731)$1rF6{A*#F8nUg7&HjdP=wS2-04~{(ST$M{BRsd@QdzyNoHUTKRR?CO z2%u1(F|vMuBHo`#m~Mfm?=nnk9jr@)L1B9$dfsGCem^LT;u-TK+&2;iv}Tp=bMdek zlEKI`#_eTvWaI$s)v|KAvcGrZV*73~_}S{HSeo>9v5y z3Zq%6awG94P-&c6fC7Re@+Ie?J#)+cyr^QrLj;1czTWvb31uPLq_6$0%EXYKnDid| zu+KnKruMIK)dmrw%9v!GW=nuO^fzkavruC7j}RdAE`5en zdl?<#!-hQ63$p*7`k#BjJD1MS*np4IS@?9e;R9X3W(&j?D#w7+0B8(#@K(iFM)5lU zGcwUdb4epFVF2S7>|jOSQWNHy6_WrfOa~@342CvV5}nM$&dDf8PVUay>GqgcN&Ix# zQ)6&91>KJcuY+%rvSydFbM+aaNZqH#N2|k+7~c<6&dAEV`&Wkw@GPGs0sXkM^r6t4 zobb~oleM^NH5}N)swpm%<$I$e4y)y|2IzP>R1q8kRX$v88PJt{MXImbe+b2r^_Q!o zj)&xTU4!#!I8~>Sr=$%-T7T016=B_Xg(Fvs4jJ2#77dM!ZRf8!j_;mgCSbl699dw< z{l#M`2#=21AA>Ovue-4^0Ur8F7z>ugG`8|K`V$7tu0fE^iN?1tZ-}%RCWrp{2D9&# zQ}G?YtE00f(RT{b9QS^`tyP*^8q=2K-D(vt?FtMsHT)*=O~aP)e#5hq_er`jd);;t zmgqk^S{r+QXD_2BTfQ&8_#Bn^Tx?nUXZkPfX}C({av7j)3UC)|Gd+y15$2%`cpMu;1k=g z+1L4HZT6AYsKxu^)zX>p^0v%Tq77AOK!(GGzo5MHb~=!apWpND5~!TJeK*1I=lnR- zaMomEo8&tkz@zNpxmq^kzbJa6AoSr}j0cW-q)sa&?jd9a7YlA7_hdzk)CLwIHH_Gt#Ba zX?2gr=g?ned(kWF?hq?o4CVbzut`?u|G8u3;)V=YUo)AGLC zXkiw}dgT6<6SOQjze~+B_DJuG+DPlSR>nto7JPb1sLIb@EtduSDDQlz!hfuaUHG!q zBZ&JQ|AOQIHJx=L`Ws3f!MAnT(xP1{)6-a(BF}rOyh6K<5dDY`%Lw<@0@o3QBK|Y}Lm}~^{JGyrr963!X$z}nFTrx?TSqO7l zzD5H*xoXIZ3DVBs-nn<%LJ*gD=h1(EGCiL4_PBIC_=23zMAtgIq?^0{vRstBV3Z5x z$TE3Xn?h@@aOT7FhdpWOBXq(dUUF-z1Gj-zDlMtyFWM`iY!70|-%pPJYFi!yw2TXG zBbI1YxrFEjf0(<`BGO$Ysfk#kt810w0&msQb7ooTdyh8c5rFlGc<~qL@Ng*)wC_Jz zv1(@|^)oAmdurJ48QE9D=od*~qLGWm(>KKCCBe;@F2dN{;qSUuw%bif8*(H+*YIuW zgfr2A+_zhs;=|?3ggmD<(pOvHxAues0Z0Z};o?lWj&wC*RB1R9jDsbmPDCUSCJU;3raH%(bt`L7 zCoJMzxOtD1oBd&vLRDJAdu!pgpio$C^~xhVK9G3~d-5q62w@(ezFGzh%2L)?3wCYw zdwH55B8H>f>3mPpjZwXFMlR`T_Jo~db>so`PNojH4EylbRKn_w%`G}>^rfGaf4p~+ z7Oi}6zX~OJ+dmQ7gv9oYt*E?we@u^a!BWL?`QseK76|Waq>iyy}1vEPnBOe zrCtJh$~C)=o!=4!5#Tl~MK_)Y^yn{i@d_7JzN)q&2R8O8tR(uG5b48oL8sLJ{f|2< zW&uJAyOSg-!u17xMtyqyC50$6+;J8Oh+%HDaqDPf`9?vv@b8lcU%=3pY0O_D-~T2U zWe@p7ztD&*GigTNz&dc>2auw_&d3)!1^xZDJI;W9A2eT72*zDjwlNOY8>Z^_&ZaMWqgeN zM#%a3^OmXM+b*az)72~+D#>UFyIMkCva919Hd2Od<@D~XPq3IK8v>2%fLtY|3xr|Q z@FXAkKn9t>73vDmVcE?s?929*Ox)VE0}cllGMOAzleWUTWof1C!YceU4CzPIbBPuy zRa9$5YN68uyY6Rq?iAfF= z{!4Ly=w;3|)TF_xpIHZ2<;0jOPF08FUe$o_>|mg*0O1hubzb)Cb?Jo3=6U=Ua0gpGu3R1Se5_b-De84Ig`UxF$f8uG+!`|o) zSX4?Cg#hup?XM6+UNL-Vmy_JE*gK{h%a3vKR%amo5V{=l2~orB1lo0t{asrn$3SDj z?nm&-hl9^qG5v_wZ7s}o(!Y?f3M^|VL(+oQS+k(jKPGEowZ9xhz&MnG%@<~KM&|2H z235JCDzl|zl`qibKdzj7_4fK%P>30W$`;d}fWC-Dt|IrDNBKAcCw>7`D~tmKr~y$h zn~3$+aeaBfqtD}>&U=$>k4b+@xFm5A=5w2YoJVJ>X`2ZD0c~x@S(D3)q`D7TJ>FoEL{ubHfk40S&c6GA2<(lBEzrd3 zM9ILXJ-XBPV!mYUDIu)+)8Pp8K_UH|D*CoLUZ=~RS@{KAJB_OvsmkrRAFcD{RfpU)rv3Sv@SPRjdFVCZ3(0_=$KNK zU16uGCh&buqT981%P+NMU5W*(1qnTAY_)e@khLf} z%f$vD1nF4xnEeXkmz1x3Ut|3XL_7TqaRNtOUTQ}$j>yQkvQYViwP%w_bL?Gnfp5D2 z(lLb(W-ypPX{^&am+}>F>#mxT*$s_h8D2%d!fyc+xKHL7R^eKfQ^ZMi%8Yh*njci? zPY!PKy1|WB+x$J6Z{Ng|&Ii$K**nv_g_BnKI7`Hs}??WNW!>`Tz1 z$LZUh7Y=?+0sx?_X1ba!`m zw@OHNcQ?`vXW{oZ^S)>1{O^pq7&RoOh{=mV~P2Uzknwi++DI^`%V^lnp(*3Q z1^gtBJ|q~$U}wDk9Q@S~q#``yRgJUrtmBs^<^=a%^&E=}e(k7;WsJbpt1j-f!U!qRWlhG;g@?&eyBf{zoI8HSi z@$JtqZoizp<#U3eo9A-hCn)$7_v5Vozgn#V6cpr_yY03JclmISz9B0f7{QBp#tOC{ z=tFa<&7l^|E~!-)E(9?h`DO^aDgBnN*2uL}|9#`JPNJT+5Ax=h4JO2l#ME~z@LhFy zML0Fwm%K>046Pq?2!2$46lWg^mr^gx{{J!p0ywzp|9THovc4(c#}*M99I{Q-px;s9Av?dBzX0dmdP)xCj92Te`omKDs0MB{g|X`>41l zbkA!6XU5Ja%{s7sp1p$f;9&Yij$H*n*+&CwwcPGwtit_c1YO>W90j(-TXym>E@(lc zeO~iw=_t}aKj)0YQE%&?&FZEvHKxFqOVh>c``L4F5uSo~lK=g&j;`LZp42QfeB zZIjo$p9zvah_n*qY0;V0a+hwXvTQHE8%~?5MJ+m<0aaGmw$uv!31|;D_*@rdx_r`= z+s@&eLfn`Io42`bK+CXbXfgD);13krXSoe$@Fv}uTD<|q*^#uJ=QV<;8?;x^+nvy& zTtde7CkSy|KQN{cI|SYf7zs`YulT?5jM{dRS*fQ8Zp#$(nIe`%Zzm_?q25bl(&+K= zUQDQdrm|_5*ajXy9zIb2qof!bRKU(q=eZa-$ZfFV$ zla4ZTIN#Cb3}2>D>^i5)%n7K;BM6dKFO7$R#HV8>=Nylms`s?uv?lkx!9c`G1+y1D zvXK{Xo)1ef?b?4YHhr#+EMrHx!>0>hy#OpI_M3eB#R8(|b|JYiU|uReMtP(P;sm!{ z*!Zw?1nNwo5_ou-d$(rzX*|mt9l6FH!uWhCx96Z<>uh{5owE0+(NZOb_moujhXnRC z^`}j_{Y3p`i?J-pK`1xF+Z%(u+5w?g;{1#0ibYz7MylvSUwdwxYJ@!Qioq)ew0;=a zKZc%niXQ>k!6%hO#%J2JKd>VHUB{(6gmZqwMk*%*6}DaOjUKrsU#={V%g#%0Fn;@f z|BNbWr+>vE2HCGI!?*?-QwRw*@%`NeGSOqBoL@q=7X%vaPP>F8dT`buC4c^W)oZi~ z1!mgYS)T1|sb+|aibMViE9NgMuFzh_G#qWat-=%C>PtqJ)p$iu25(W1Nnagrq zlV;y}v*LOkVlGHvaWliU8CruF81F}7vp(DGTaitDZqn8`j?z3`(}6rsa;i(qvq(UG zs3hwbyB#)hIe7WG!kY$bYaj}`T*s3?>rpP{XqS(vKtVj!4L~|fWBG$kGCRxowSS?3 zePjo3Q~nvQ_88)fwz1Q!Q^8rr+yR`ynilfj`J$2jpjZ%*(Wm{TD&-N`xG3uMc*;eKN?0GMG5gzUBq76>W8 zV>IFy4jd5fxh+DB-<(ANyA&=9&P7*oEcsti{onr42%ch;H)y{YsJCCAo9ydSXLgDC z)4C}2O2^_TS=9Wb+vV}>^~e4=g-u)uJ}dYbur!+1Rv`=n8}%VjcY{-Ryic>%q4RCI z$y9zVJlz7|r>SV2ALEig(qVb$_BZ}tfK)>0x2RWu?to-}qSF^eWJ4K>K=tds=k>inmOf=>?g{jxKGd7~}xR2}zau)aY?GjuGxe8J^b$hUPiYFlYSX-XO?=Cka( zcW7ug>fKkC&nGRL+I;QTd^}Kpdk0O;@(wZcmDiC}-QHk}`emnl&@jz!&t)^6x+NKg z9Aj%JIkkrzkKZEj+KY1FQ-1hHO7wlhxF(b=(M&=i#}*zQiU-|OF57Jo$`#3Ed&L?1 zUEBEI`SLpZ&4q{v%F9!%NP!u5fjR2W--EK zR@7VXuhpv)4r7$lxXKd*Yd4r5dDwFyeBJ7bwJ1dDBO2@1nIbA?xeWw+z%n=9ygAjB z6Q6(kjSL4YE)7brV3G1_l-()3$XE@@cq5Ext^0o)ZQ1F~l@jLrg8#?VpcD*mwZ3L*LTT+p8QFyyBixWI}yuqp=eg5z6rzRjXiaNu& zrjbu6)F(WTkxN~ZDmju~d0ACeU!>H;h~U4iV&H9}Tk2>QH!v2eXs{l3J!) z>mG&(WBrjD^o72$8aJM2_)Mqv;+~HWyw!CAt}!~^Xj@L?56T629_M^UhF+H#d9F?h-mWv5l7A&!I(YJWi!P(NjC*FX zC*)=Y(&{0?eKAZp-q=x{(NX2?Bsl{^tH{Fff}%4HAH1x7Uc#gHue**pXAvC9y+B%lALy3sz0 zHG502NAVkBJ^5l}bKVX0Lc3h^_ApvrzCrkkD(ua)*5INj_&Y}ai5ak42S99>;Bkcp zaaQksiYTmH5>D((oRH(=zwdc8o5XFhgOOYS-u}a4(Ppwk{^X+NatS1y)WC8hNw(@6 zB<>{oBzJDqujK8gW2*G~v~N4^qH%0Z3Qs;6PZt(WA5V<%3m!G{cYo}lg;GYc7cHgh zw*Q4FBw)@gNiRgXK1ZS-<2(IEkn!bm0-Ml`mx;jwC;+;hBHi|`oqI)hN$NK8XX9ZCP zUD~h~Fb83=08y}AU7rrqpuZ~C_w*gTlIR5zu2k@p0FJ5c=TJwA9Y#hu$zE_#fciyT zr&fNg&sg=`H~%$3TN}-0tZu{T5P1cE&6>;ly0SgaVt{198I)PZbmwyx~Vaf zp)}jc#X;9tTQn5FeBc$IBu|iYXKP2 z-IOAv24dyRj_Sfu6DbOly`qudd(!fNzQ9q}$9kDy0YSnk4ZkG4tr?u5-Z@W zeIrCn+)@fxjC`9zTxfc!JNG@wrY3oueNDYoy+|)9trV6vT5~1jDd&Rn?Vd=LBSV{~; zzOaKK+(Kt!qptmU5QXyorhY(RBrnv@f&Ip5Cp&s+yK;^0mkV>F-^MQuvBbcg^k%vK{-e)Z(ap6VeYm3du$UwY3 zzyE~8F=_PyvkLO?_!H4+=L(?HCRd3l86n1T7ic#OZeu?#-bcGnTB>YQIi|(sFL{uW0g* z^u&yX$AtL$j2fY3BxS`15#47(kenK!-ZC%;f%KDMiw;hWuW_HLr1!ADjS;=q3izf! z2hSkuKTtjsF0)<}a!^*Zc38K1Dxz!zNj1!w)8(q=P@-IqY3vzoVuxZ~E$B)=v~kGb z!u=BIF_$h^1}||%sWHo*pz`1C+E#E-nZHYX304_E7T+nXkD~0JJwq-}y@6kM2OrBuz&G>bl}b0EPayqTj(- zA+mR~LvtLx+UOaM;!5b*S3*Vy99Yqma`u>F0+Rw6BCuyh+NYbJydl;cN5s_WGEFO7 zC40wp|0o)|0;yowP;O_k&2YUZq{!R(Mm`NO8pkBntS?bDP$|RNWkpPSj_{!rh z(p1yX7@DVcNy_0N#8|gg?>s;T^#i_m2G3w9ZDp?IxaZ6lX7+}Av?7G~^ikWB51Db9 z;YynagXaFBNz0ezi7PF_2Y*^-n%4B`%-C@j6d>c43^SN4`^w=S8^BFqXWcNS|KC&^ zPP9bwJD5sS2%DW~c6+Dhp3<#vXQBFDaP;1KOKp9 zH;~*N;`1JE&v@G}bD!N9{W+N^hzMY@gM|K*65pL;7Ok{cuE%SUve%T8W{VF@A#waq zwuwvFhVvnXztF!20x_E7UkQCC>DN4yDgx^?6eM6%sI3@cM^MlaYv#%_{QeZoGS^&| zN5d`^>K*+4DZKJpmre0b6%oSFGmI&d~`5}099%kP^BPWijzC}zaL=j(+#O6&HTO7PUEN2 z=x|d01-paD@71}{3#$g(Lfhn{^-t*#J|*5}x!AhR9V#ONNW;Cs?#h31(JRvKQ}Qrt z=csT-{~FSyDM6~T8*&?x05h4T<;+Aoiz}_!%2D=BSxxS7g5WmoB4er39|mqrT(?0`I7D0@+(oN$j4B+KAQ{y9TZIo1oqA@jrf-inS=E%zLKySfr5hORB_sC>7) z@czisy=S#d{nWd8tmJB1f?nK_W4vnQAVLH%!-BGIfJEt!3WIkH0SZ6%Adk>MauVCtC%gyG2S_j|Ft>6FsQ*)QFLWHim;5Se4D#&44L?xPd$TBROHjWyheY53k1t&z>w73B*2;t%yx(fuS8MSpDm)!KVzJ7|{oV35ij( z%3*|c_ZQ!QWfPV&8=Kg{dL}$9Y+;2o`@NsRTvVJPL068V3f~%<+|(JhF2yp7RtwPc~+hD z2Ff+-HVDtmwYR31*HiA*o8S!v3SZM23UFEzV!Ks>K07|`XTt#c=qN0W3PFOn3wE5V z*-@1b;z>B_Z6bXYi(#_-1a&SIM$TK)BK-UzN|}&O3~Ndtb1Qy#sLOqp z>aIGiGWcVq0EwzSAv2rv{R<-s)sr*cPTO!(_qI3tuTSkur;Y3llN8U)iC?5qmb4+0 zL4=O}>Ch4BKGpC3TE&9$wwH{2y>Ax(#MQQ%WL-Dq?KmoIG?1yiAse}UQ{>7A#|*x~ z-G3?`=08n_{}JZZJeXLASNJnSRi!egVByi$aGRPi^6Aeaab&EEx{h7|NE~&hPNkfJ zK8=%-u&8S4H7?Bk;6e(vl036%F)w5_!Q057V1Z9dwn^2mu%8Ppgbxqko+k$meeKxo z-fR4H{g0Qi-{^&7SznK1X>dLd?+UR`O7U1^9k@#v>Pn50{!pG^)H+|fEfR*HHo~#- z)S9Be;O5TBGXHjd;^uqltwhrZ>@EzS@jlzt@@T+EmdnF$n(HZI1Ftk7i$@>1coC83 z6j_Qz*X<89wE+?6%JM+7n+s zilj9ky?(6fVc5fI+`~ye^!=A$JNz<{3*uX`i|+1VL22auAH<{@I_?`6y}_gu$;Woq z5XF}3kF=G+MXmN4j(w>gMsTGg#V_eHXXNiT6Eb4=Xp7ER%$7F&;n+r3;TCQGWA7o3 zSrx#4kCn>r@_p(V9+P``HWF7lWHRJ>q?%}h)fH80l)b5Q)wUCM;$X1Hb4y42soFNuoF6Cc$5`Zk*n(TKczDI-&T9ug!m@CxO= ztN}G;BLULth0)WyJhdEG;veGP&a-c-o)J$22Z+j!^|4rL3X)?GOyFQ!`ucU z>B%mB^eRAUM6Q$L-ce5Tf5Koh=gu~*Y5np$(eeA^_qS85;pUNLR8*F6=G*Y#SC5>{ z60UR~K~jkx2~h%~2ER`be|!JYRmu~q(#-6KJBZ~r(dtdmBa-TRFAn7t{5%5z2}6r% zsV;QH`JjLJb&CLK{t+81{*gi;Sf9Q46FrST>!FjUu}uuR^F24lugk@vy-VLYjL21r zNX{HZS{wjYLW#>1af#aHueU@sE+!OxExgar^;$>;-AqbL%T_NyA|e+9)ZY}i*3lIC&(9QyOkx)|u0zfweX@_%^uo0uTW=e0#ZK$g7bnuR zhPVs3gJ#RY9)QQwB;nccX|~&d_9M?x^pKWK7%yfeemXghTt)A-Qmf7X7Tv+`=YEqq zou5mKl^gABHw3gPb&rJeLB9N`)XeQQ;hwm7pQz%kiiWdips13hViOlFg_aiJ69_<$ zHj|O6nYTmhG_}nCU)xE{+Ghnxs{vQf)&f^Ij@?x`hld zaOXE)@!@V^aAx(_b)uf}N^qHd>0>F1C2dBvlE}9aoR!6$Dj4bb*zYkeaP^r*f8&t@ zWY1JBHb*4^B+#ln9`R0E@*D$t4*DExO5<%pf(^6cYx>x#y-m#?!L&l-M^nWY{|?wc z{ty%x<0#GE@-$NaYEBHh^e}amGNzbnWkf3IC0qzS>@fWGXDL*7l0~t}a;|Dc(3=PA z>`+ES-gHN(FeLNVBu>>&D*%wx78Y=&KjL)xpv^)Ebsf+DjjHN>LZA-GvfJi_quf3> ztL_N8ebC-An?^9geu#=9OmI=G4wF^7b$;N#)vQu8FPcKbtD;Lc8JhA~$1eRtZHB`U zNtkXs^9C_Hk8@{@oUOBQKC3oq3r}YMa)uOjH=arw7yoU){A>Eb<9z3|ltU6i+gA-7 z7Z6DFs&Dm|m#HWV^0D^Edaa6J;NLCNT^tWrV8?yVN*;3&)u&#V(0)kLi%+eOU znjS&+Eqec*RElW@Hv^fu$DM*z%R%w=-r=u`3C8Onn*ze8l6-HUP1v1~j)jKnmBiL> zulpa^4zmA)_HqGe?=5~grxdnOfW4PolZdMGx4Px|8{m4BkY)C?z-RxOosUi)hZjI+ zF|!bC`!Ws>1;s<^)%T$Qk=&A+Mi|!HTkDZ7Ko;B-FGPAlIY-f1-d)10*cYj*wnr{v z^)t80t0p>#(AL}qVhX2zF3n6IP^~R!@T(yP#~%&;#XnKvIrPrRF)DGJ+EX0#TE?GI zyfbc0Q!2AAEm8`do}1_jQ9~p$kmCuTHN!0z=br5NX!;u>FA*>X&r=ldrbo!D`)a?< z&$$`>1j`N<_Pan;Yd5*hB?iG7Dv{q{7gTcpuxUaF&l<#jw)hLf?ck}F)Aw^-UTz-t{F+kVSD;zt8@XEqNHl+ptNal{cyeZmVULp5 zD2$B%V`iRay^`&Pnn&;l;=za%n>?ywp=zB3iha-m)Dy7Ja0+N${gHV;H^=-S_rvCg zrSddRLWn||7ScHGzdX`7los|+)NAxU9Kql zw@mhv3as1YbP4!tBt(vz9nZX&0bc-Q2-?3x`R3lIV86MadMLw1rvH!;53bpd!E9)+ zpe1t>YrANEf=o`G#;KyGM880Xh@`fl{3}Qgw6wrAP`+ocsRk=aW(QFoef*7_{T(K# zWq*&RH1_>DEP~@oRi~OlZ5J6>;_GGZM1YfsuOF0|Yd)vhEzGML6y#4oI?n5rG`ocJ z)JUr=PGXYY8#MCZrMr87gIWbFG|*!`Lq&HKmq9;b7h56^)h7Y}V3$Z%(Y8h;2zzhD z@v;{TGIb~_b!^p`^^(OISF7f?Qf1q(9-r1OwsPBpF`FX-Jiz_FDy5c8Co|o1rJ#&l zv>~OZIK4N`+Qp4I{5|l&2@6I!L6UGtwsmy~(I-_u;(^O~{PAnJU9o`YghvkH>qF%^ zTcm)8>YN9UfA{V3=leFqKBF95xbe3Iu@rvUTEk=v5z}aA5?)`OH?y+|CH#$TS?Xn1l*k<|Fw5YN|&Z8nbQcqdu4MOg1~_a2cTvs~oaUx~sha|5UggAZyO|1KglC$dw&7F+RSgq>?|QCJLo3>Gk=cZfXs7AvANQ z3R1jIzEY#;3^@^ z&xdSwvi3VHyDx|&OS9KmH^n=|Sy9qg8tC64Lvha8qF|~}sev}^e|tJq6KfOQZGl9c z8K->xR(Zf=O=f||EDw(AYp%g#(kA*zpV<@{+KWigJs>={c1NNhqIeHo^|M@eQ&W@ExpQQh%GN~Tt$C9@^n>gJk0!mDu9sucyHkS(F|y;bOr1l`H!#A|?eANvt>nJ8F?eJnl|5d)6T zDPDbp>9-$?o6z*cdZnA&@-=cRlm5$}EUtlxV&_D`ncIqq3U52CLa3NR23&G4^n!N- z_h82sP;nq6cfv`{VcLll)IoekyaxA(`I}qW#Zw}EX7${$*Dil9`Zl~yrOC%rst%Rz z+lApVIs;qiAheA17voeAT^?-B`?d{n`9IbuTze~3W}dT{G@>g5ZSQ|G!3!hagiEri z9H0yPLC<{kDYQLpE~KLt%tqe)4F?l?m?U6e_svs=+CZh9t6KTeRT2UjY_=3>*=_m; zDv>Q!!4W|NG`&NH>Ie%}Kk0dGBOZrzQtfTyFLh|j+$2(xMRvGOeMFmzS6fp+T#$TPCE;`nRo;yHGun#vi+UkiK?z2$DB^qym826} zG^0AX{i{T4m|=aN6G*B1&K9+shu92K^Wm^blnA$%oJb-sAsn@+LwvWQqGXz~9k(#s zQRXlIanz4TwPQVPdprUkv%NcO75nMEE7*Ee$F00xY89sHnvw*#3~^JRI_tNpqh@8n0(I+gYVGsLvw01g!WbHf)LWSmc4 zd7;nl>pEWkJCW$Nm?{Tcu4yMutaddcry)(qXlKo!E;u?BYN#IXb1lDHpDgO1uQv#l zL+T^B+;7wVsY#<=(sE0$F;`&0Vts(f-eyt_E(Y6feZi>1!=>q?aKUHn z&caI9r-3E0x3kiNoR^>_S)4b;{(E>wjNPLo2NG|UCSlLxNbHJyMQxlYrZlm~N!{o_ zyvA!+9zlEy2Aq!=PG?wC?#La11BktHde5JXwaX!|kc)!)kPEq^mDE>(qI10UNvV%O zMmsjsgrV&w!+8RD4V&MZdEy)oiyL~L+_=#gH8YBbyj&{logD-WWeByqmJf|>irOFn zx)zFu7k6t9Cny&egl@4;Uu_;Pdj*3_)Gi*i-PfNA2Hu+?IM;@dlKiO#f`EDHc%dg0 zw~D`b+>pW?x+T{ffH!M6tk^FftFXr#&jvrSNs* z!JP#&$HH6-044XY66HnAh<|{m4%mfYaCwP z3sT<9rlRsBnxAT2s53g3@{2!%BF*zN24B1j4t%Lqno_(7(2}Zy5ld#j5Fm_~a*BZs zG6@yMMNl!l@4OH2|1~Je$it!7HxzU^PuKD$k3xyA#$u3haPi!k<*RN{y^qe^EW@Y# zS?o6HQe&czeYTRP{ebP1!FN#H!NFi@XkCJTXq`!Z zxx7iv8M5G*?xo0b(FVyo#*3{RJ6JBMwh&&AYZgE4r_+9|lr&Fn3wmL3h(wgc?l9qG!4kEMKSjr4c||7 zVz8RSSX;AQ+EcI<`V4d4UcE`Y?AJF?Dc%HBT+OTq`tB$xTJ$8P=({w+s?M2mHmzkM z%-aZcm|6XI{a%_XDHC$vUf$+h_T^wB7p&|2_@fMc5yv`*DzZy@YEg~((TYBb(an<@ zcQb(ImRS3eArQjY_G9`bc=o?TZ&RgB z+aB=({!}+>S3T*VY>Kp+>G+k6!~4Kp2^u|c>*+-17t5?-`Q#>*w8DE0Wv0eN@kU8P z+n)+#oC%rMC+TK2!r@FfK9JOjg8Zj&W~b?r&QiEH1dxV=XV4JjWle4s*j5qe^=zcU z4cmYNEsIhEKA1q>8WfkjXx~bNmD{RuY?JW$#lMZg_IJd2br(3XX$k<*q3-Q2A$Ts* zOYx{$VxC}$Gb28Mv`yx8g005}^6WvG$;@jFpdhlOev3|vdDvfQ8S4AtxzWnt)-+qI{y2AYOQL=3~FZ4>mX zf-2u16{EkTB4U3K*H%R zCPI=Uq%;ci+uxqJ8ZKgRwRzTg$__5)oqwp%*P8pYIO7X#4=oa@jyNmz{E306XoVla z?2Rr)qorRdh6~i4U!w0?OzqZc*9qk-Sv%Q}*7LemE85%4H9^&?P2)}DH9@(Hmm0;p zs4*`JACZ5aOArnNcQj(sLi`N`J=fT?NgxcEXyL_vhgPsZz>8abi`6boI$TxTs7ey~ z7QkAobzayXDPzql+g65&h(l_HzCLLn{h^W=_5BsvA&(hpOI(ljHaNTJCSN$Od3_EH z@^M*;%9Ckqvpu;`CCiebc-1DAAU_v>>!Zojo$(}TEG&m6A?x)x&R92*jI?GM)c0w! z!U*`;&=ifeC7;kT+kmnJJ?3Ewfz!*4wMEkQgh;DfAX_k`Tt+H{fjF6BtCS%_{TSft z9Wr=+xMN9NVf@@7Njp7U+|6}t4cNHSsJ{xIHJsLWy1}|7ydRX)j`NhS--Gv5FS&K} z3(#7{Wf&M#U&jb!A3EcE`dh`;5`>3NK7vJ#J2=2RqL`)wgk2+Bqo^2fF>A*(>J_B{ zI5~|6@ge2St1c@*Tu$Bzti%Ct6`Vs)lew)-V!XN%S;3Bo^ z*)}LjW9S>n;bN@yN%E2LC9yz}9n=to^-v!=o1Ye^| zM|=VtkHA3Ny27&*hL;HL5|bgEc-Hs<{Y3Eafp+|mqZSTxXSaVEYx)B|j07pH0BCu$k~hK@$gPn^w0B9Vceu1msqZNU>74FH?PSkWlCo9qs&mF z)vj4$M75YHIW

N|J?k*Nvfwl^kk{!-wsX&kSQo&R}b}4z`Br?eDBM>M8rJu<7!Z z^Bfmjmp5k(vtZr8HOAd>qYgsnG9?4Q%uAj2 zKTR@HC2$!e7nm+X`apa+DAvm~jlYL}YN0?t?Tp#j$7aHQhpNntI5dT>`V4XH2DX5P zFYOa!iUFF2EMGdf@27IQaaO8FGaR^qvmGLgY`u;=s6dl-Nnh&VdBTp>I zz27P8nzXX)QD8F8LZEwlAd#n*Uahqq^tq~QFCzK;2I7^{n9#x*Gjb?@eg1NBZFUW? zG)y;KntzOIt=ly>_-*`YeS&)7h$d_eqqj|lul??BXe!`9GOD~fWv!BcOnxS>3+@*F zcaB$v?iWd&@gKDyEqE}a78|+&t3`HCBrpTN9U1-Vuu_nq_i5F+iuqmpjdWpB=p^k2 zrlatEdq|~m%uzfQ*DyM`VdtsDE=x`pJx@Gb{6r{v%BIGgvLb3{IPRvUmw)TgkQi=>-}n|!ScNjqkg_^Pl@6~T^2?2h`If40jES) zQ``~QX>Z|TuX2}`Z!5Lq4lg74+L9+40VV=kvuaN>-HSl4{38jvw=4Tv#UuG&1CoHZ z=$Rj%`q~r+8TLP69oXh{GN#JrVyVncbl+@wVu*vwy?Ck5+2vdyAN#UkMowJ%c!N+r z#1GCf4UsynVe~bVuQW+P{^}j%kmf?;<9tnF4B-vfg&9`OHEDp_M8zlT4ltVOgtU!} zW`o%bWAq_UMuDT-$GUx-tHn3PUrI}(7>w1Y2VF%Qd92bmZc>HXQ0K>Pd`xu<_PK_i zNdXqW7M--S)4prD_8-@H5OMnIwLR3QF%7p-?aR70^HT~v8m1gRmcYVo8sVe%eaTE< zuFx##CIggm47Vb!t9Aq`-&ckZ{5y^3G}g7IbnGTO%Wy@s*oS1osMVNC{mj_3(lKcZ zSTkQ>nF~bS-=vHn4!+5AQCFIX4%946b8FiLe4Vc+b#(@FIv}K~#BzgbohuAt-G4K7 z$KIoaKIm3%IsR*Z(n##j;F{f9x)(Eg<%uk;imdBrdQ=nU$Xv4SbDWBvJLHTNJ8c zW1B6IVck0BNFobjZ!nG4e)D6I>Qs5|5U__&|Cum-mQT`e+!Gni=B)*DWUEBaBv$W@ zi#SpMA}oGchaR?EqiHNiWy;`mUzcSSddq}DB9`Yc$5zFR8ksp=J(#PV6P4*ROms&I zmI)uvYn4u$e!R4kc3PvUu=dTs`QSZ9ZqO!j;QKKM!8gqg;2ZF_S+qr|8SRn&5w;aG z%Ev*PFDF7Qs&?-`5h3xOyLeFq?niX-&$ehZH-(|o15?XM^gnQ5kXmSqHe;j&$N!}q zGAsP=0P1Yi!xpY3>7W6gW0Sj&r;|sei~D~2O70VPIU?*Ij&5SU)zd57=xFZpgGr^n zD1`sbb;(SV6|I0na>4>1V{}T2pL=CxSy0=yxodYgmHl7@0aveNC}DV2K*T(EPp*1* z3KaeDuxX~-5|l*@J3-WJl>Zlk&!7BC*)DV)H#X&T{@yKNTpWwktygy9dzhi}31(ZC zdE~`=uhU`sK*f533E`Kc$yQ6cCfZ|;B1q+LrHi@ZO9muBb>6bB%n~WK zddyh2)N%f14AP=R{Zb3yt#>;K<62B|zS8r?)l7@vguHn%BJTXoWG%_h2Q=nhx}3cv z+MZqHNt;%YqOKqYb@P{BGNQr`3sd4ryp-b7&&G?sFc&V#eW56@g|im_iaRaO_X$|0 z3FC-T2<=g=?=dPnl_+l*l-Q%vNBtyRNsjWDXA*F$AdCMG#-(y2RX>l6;2Z|RIy`gB` zn6{P#EMN%5ATHpje8}z}6cPTYyeIc&_BW&nksG&OQHp6u1ujA@`A$R%RW~b)5UAcd zC4J%x4#{E@NiSFGgykpINn7??I;v9L@xl~$u%&AA3?aROYZd3AJ|*aE!l2YN;* zD%Q_rygo*+t^1`5XgxZNT3L4|ey$06DDy<*-MiKg4VaJCzT2$oaZ(PFQ|}|)NrG6t z*^Fpzu8CU+DOm7d>@!^->+afkhIZ;Z1bvb5$X7!H6yN_7B!C^EZQI z^!zwY7R>(PqE11cqmnOF?ZjRj8wz+y|C}Gyd)@CXM_ZUN$w)zwZZTdG#Rp2?aykru zb`^~u>Xf7eY-@e-q6rm^6WWZhZ?E$*mX{N=W)7EaxO&iEs}XPbZq4==5oZ+^VMuDMMm&#T zcCKbU;*VYn?*pQLlLX`MuwuQxmS8qY>wW&ZnLJGD+~1j}W z8!W8_>@yAPIwcjKk<;9|IxLMHrYz^9OQ>!`Eb2~N>v)d{zv1sc-flYkQ$e)s?Ybj- ziIk5A%XO~>={|?fcxbkMz`n!oP@APdXSak^07)TtcKUe?JUmTl_h$~Zr%D~I5$GgS{wnsBr#+1 zrMg*&NkN$t(45$ zmTv6PyG|O)+Ji2}9%Wu*?|1ZbVU!e&H@(Q}$t6IRCq4^E^zmlspZXrV z@JP;)b__huyPmRHXZeEfLBB|+KZJ2*DHtc376ykP&+p9HI~L%_{+E|PMsV1&CSGdmiPdY^OGS+t5(M}7Zgb24 zOC)GeTI^}SOl6$fB$G~C#=X=WkxgYFnA?=L;tQQ^uuWER=j1(5? zx1A}Px{Z}EvwIa>PB6Tr1JdojC#hB24ySWPeZ*(aM+0AUYI;AngDv^?W*CXcL4fIUJzxf793;phxAm2IOwTY%$rUIZB{aLGN%%wTX`R$<dj+rbvly;Cm^YriVq9+cR>p*Lp#)c>m~ zj23n5G=xm=C&$zq+T->p>iuPP&+=}sCvnIUvtG|KWO)M0=Q77V+vDP1`0vVoe7W}v z)D%y4X3{#%4)F(UlK;8N-|66mLHzNA(qcp zI?ASK4GxSW?9@^aLunYcxoCKn+AgRjT*P_nw(mN^tV}Bow+t7)I*z2Binkbl^I~`s z^Yw?cWy}$`kLz}}3xlq+x?TGYv&iO2=~w2&g6Whfdk7eMz=`_C`4SkR_Rm){*f89w znNsfNw^R5Iyzc`ytme8r&LMlV_*bI=Bd3x^gW_%$t&}|;e_?vfSV?Mb6+T$CmP5@Y4c7k=5R$AH63OkV0QWfM zW|54@v*V4})OvkbfBh|T?=MmE7tBMvS9%>k>p#5M`4WDNILbfDpE|sgwWW+3F>^2o zPgJe1AnvzsBUvkeZP)MIU!Cko&Io!Zma&VNL|*Bk>2|g@?`SB)IZwK*gX4u`7gWZH zSItR=k2zy(vI@x9ATmW~KRdul+Hd`;a}v$*(A>~9NV`WBx~%=X&E47_&w->uG@Q5#YWm5>BLMuaq4|(DanD*sKy_0S!R~!=O8+AoTQJ=;xFJ@OeJ7ahup!CL zDwg^3=EQOdo_&G(*vzLH@++ue`Yn@>^lMJcYDG#WAT!&j)l5!&n!aH97aW089bAn4 zC2J4K0JqRp0l1)273x$qYxV=SVzepuQkJc|P@RtV3eciR=b#vzUPX%9Vgpi&NM}-M zOPE`CItRP%;wtPg9_g$GD}^@`UFy8QJT{<$UeXU?yrjm5c_>>`c1_;g$Ai=;xQNd) z4_m=*-TW>R5Y>XXlKI-^8tp;qHO(D}7zONh1i-;v*kV zI>xf_Cw?bSdE{C8)nl;AIh;=0#exC-eGb}1Cvag4F#?QOvp&4uv1D@b*hq!ni+nwg z{f?z6>E40vTkdG9mcmbsJ$3SS6-!EUH)ya-jwEh^?$=?eByOa`nIUm|dH;>oHW$T+ z9e2(#Qfxvx^z<5%eLbK&VZx}wc1H0`PI(rI2_B4Mfl~)gR5w<5Y z`p$lHd+-EGzAa_T2Ps4kOBH>!)W8L@FTbQ<`HK=VEw4n^xoo>2B~H*Rm$wQw#Y|); zRH>x7m#~4ujvgLU*K7TY!T_KeDOfH_K zr5;GlZ!csZ1eO7=?}+RKSN_72GQA{dDEfH}J@$w&B4@&^Hc^cdbJ_E|WMc4Bz`d_J zLHV}&0}8yLE$D=+L$c1Es|?r@P!z5Ir>V0HtD+6JFd-!(2qGYoQqo9=5)#tg-L>hG z9J-~uyV;<0OGt=xY(m%|-Q9Htzw2D*{GWgG&b&{ob*~a`$~I=l`#e&|d(oW3X4%gg z>>JofPl*ff&ag4`l^)Uzx;h}|*%bm+#wwdR$OH{+^v)JF?t(&6=71sk;efqUTA=}! zflKaG2XvC)F?1C2!k)>2!Gz&4-lK4DJ^qUgsprWXY*0-=+-(zh(reE?Cmx`}_AXFO zEXZ?2orLXG&(!|nk4RM-WAv9^Sm^OPQqA@2vwJp5*{I`nB%pZYmo^F*lGgM%QGFVK z6Z48N%UR1{(h|_hdH$+?Ue%^yuGe};WL|&8CGU)arM;F-Xp(a_hGi6A=+Dda2z8LM zHz$sBWK>_X$h4wah8l_^k{oeiuM=8+mWIN78cH3K)79MoMSO~%ajCl^(!s{?%oE*o z8B=vQWnFkR{zuT^KI&LcVy*T>AqK8+dF-G@O{%F(G4Xav>#D4zC6Ae($V`H7$iI@pu28oUI}`RIL?Ytb7AJ<@sHrzSW4S7xWGTJvRpL7;r8DoGZBSyeiExvoEx3*wt5 zTO{u(LRlWH_<@{?G?m{{Q;>+#_dTFB4b62N0|x*{hUVbNkbF8nh*7KJ-#wHM8bAu% zxW4Qgw2*e1Bv#ZB1%ffo!8(7UOVgiONjjT$9aHn2pnm_Cd-YXe*(GD+pAk>TuK`Ek zi*CTetZ-LzTn!Eq+JD^6vFDGW71_0Ir^PnB`jt8OYhEoB7xIjQ(Z5RUXSArRn|o`N?CW}7LeMN# z95auatlU3jLGoS+|Lj(1i~30c_o0&(dBYna>D)DiWhxx?Pe=YGtU9=w3@-6@GiJeW zzL9`^<2jyH{F_T68%CsWHjyxZ9v;XKZn~{BEr11^CYJ z5pl6tDbBC3f1UmOyWxg{e$byaya9Uge|Pc;9sVCUsP?S>DC?ls_o5&C71_T{WV6`^ zcwe;A-fYnazvRb*X5#-w{)7TnvT&uRoY;%P`M+d=5m!oZ*np^vy~g%aRB3PX(T>4W`Ya;ZnY|2I~ODpI(iD`P`0uFV-$HXYqP6*K>Ic zfF*^>uSWXEI9k(&47^haTb{QW+4Bd>vPhDcOtPqCiFM00u|FEUk{ia_C*)_9=a zqYUwYOoW*@(n*@X^aGMG@7U4f9km9$5wg=QZkTTVZPF0ACP(jd029y~!BhNF8wdj} z0(JvdQ*=7z42v;LIeifBmO9*O5-))&-@W>oN6gXb*So3|xMPbR;r9~(0#4U1uz`4S zuB%EGz0OF4`T-FJAz4Be%Wzr z;z`}#wNr#9;b-6s2qTxQg0Op{30^RA@C%V(zl z{kOsAPlmr8K)m~XsICCM!4(@Nv{BvS69MhLvOV_1wI=T9K`Pp`ES5C&y*wPG=g6zP zh7;RgANLBEiVf}f$asv@KR^Rj5JuANp_;TFK8@*D44SwvhEtqQMdZ6i;BiV-LVmUH zf@@gtY?x9giB521)frb$l2j&!>On4^I6Rg{W$^8%Zn+7br@)Ls_RlTp}>v@Z{v;lA_*hHff1=MQ)<~;1TI>N~>$W&0y+V zM#Q`JR7MDKeZZQk_I^CmzSau&MS^o&xJGGQCF@E{RLHDBS?nL0#^yn29tF}Nh3C=W zu%0FoC~+zW>gAuO00Lt6Q_$a~dUXrGByLr2EP}7gWcRh1^lNU0EbhUEMp}|py_|=D zHao#~8BF9$hQt=TwXDi_lKB#w1%otJ2;oo4YvL=HqUTj_Qi$}bR!)rEHm(M{#2b!5 zd_W9@NU-*WS!p7#vMh$zfM=E{<%w!r8kzUeLkS?Greut90K>XwkeqKwc+1-EHkmxg zf%FNK5Nc$ienk+y2JJpJkb+n`P<+rOE)U5CDXlEC8p+7sBo7Xol_u*8u8;WwF<^AV z$cP2+X_pFaQzJMab(R}KxYl4P?oH?UOPbc4@tWSc(5Qam(}deBEAs_5`iJl+Rd;!S zm1EOLNS*qR`jV;LzP5Ovw__n!ur~}ePs6QdvB6IuVk(*k=KB$Ub%J`LAB>M$^rWkI zAte}W|7mc&(d{45c6f-K7SJ}DMQNn3x|p*50Tb(%?JixdL=e?b^QaN3NdZn<%aV-f zv1eVSmDMx{3$7VUpaftRVm&nT6kx2txDE9%Dp=$yIOGyYSEBz<~sgc0>fJsRCWM*nuZcv*eU)nPgclZKye%T^-y259YZzzYHNdB(bF z8RdE*S_6Bygp)AL%UC>!yb~CX|3dQc`M`*oqA&E|X(S4AvAeO$H2`+XloE-$c!)|> zAe(R9H1;71-+BiFQYM3L%J_M$qP9Nys~5veH|R_?OM19hWe2fc#CM88Jy3#n_q+!@ zy}v{w?+8D*u5w?3a{#Y*_p*l8wT@AeCPd03r~BtJJ=k^YhjB7F&`r8sqVRy(F5PyA z^%9;#qOlk2(fgfbvTGG;gYplJ^*(oKQ$znDDgc(@E!F1m9c#MY$8~!gD#gdKt;Zti zQb%azZ9_x5L}l@VuKgBZm=o0U#Fm6keN2*K-=624|`db`3bJsO5r$ip?o*B+K=exTfTM4wi` zj{FTB-y>qw-T?iFA7BXFu@FsK5@0x50-z|{!z%WkIu)-!AJHGoM{SyizIN^tZQf4- zof$|dP9SHB2=s72yEm@+3aeR=!a||A8||2;fZ<-LbH7w zo;8vHuY6E!*}->5`~7bi&3+=gA}Yl4-ZLX!P`Y8sbzO-v47VCHW``{91C}2N2yP1E zQ3@IqK&S>ST5pMy^Rz)NtoUH)9Zs>t5oJl^e)Z}~_)e66^N#a3v#1tnJcEr(KQN?% z;g?;IvGg9{41U^H@YH_Vr;WJhIVm9op(+3^Z#FAkP=XXeUQAW{s+kti3>4H(m?rpF zXKsoDd)7nevVKpXjo9B^RPMXuD#$#9CLOJO3NZN~ zfp)Ws=`0f3k=w$TO%U+_$O8?VJ z_Rkl>?q<@aD0r(dwRb;9g&uT}P0LquZQ~G%+bAs7MyxUxtE>q~}Gg33Shy7L6kc3<}d&D2}%E z8J;*h4;`+OYzPKbV;I5afLQV4!hAdeL9exhn}w8pn`x!h5btcR+k;cUi(CH4W1>Vz zeP{JC+hva7)+^m;j9Xp5`}Kn3$WGD=@?KetLr~q35x;)!UWFEm-vPM4+S@YW@*8qM7HmDi{( zmp*9!OK6f$AG>%z)-3b-ulOU6Qw!vA$|)G@K^XNwz`pU)C4oI&nQ|pVsL<>oO)dyp z2&my)2)NLgvwrtfg!=m%--oMWRYmY(3-=i^K8B9GtMHP6iT@dS@wjloXjGx*ede@G zB*gAA9n*11s8*@$SI+V=y5dB=lw0@cykaCT9Qd|ZW2nQOeeDshOZIN-BLZXDZ3dUr zX0V!SP}E$!kjQ23vQlA}8h`YW z(|ICqaxUyj`fpcfemnzh$5M7t3h_<}XV4rZxYon1L(9`@8+P>fX*ShXt;p?21{MIz zW-_uaMAhD@kh^Bu*P~mh&Z^_KTO~0ad8u6yZuVvYT11|?Fr-;}@Z+2Ji}NpU`+m+h zqnOn>d~Z?BEFGMRC(|#b&A3#@u^qJ80?MQv)?_DtgnPD$$|zJ^#JL?2v%?+@k>=hKW;%x1 zvLl(k2JmHV*bndTfzo(L(|nsFg01g!DC|%8-U-N3WL&LQWXn|L_)E21Ht(Yq@N?-y8Q~3n8wpO&NGnO9~I-n z6HR|Y3ZxKmuGf@$fpr+UfmbL3dUO8-K! zT=vp|u-OL^UH_vXpmcA&1DJ9>Vb_WhB;eb+Y=0`xMSJx=5)j1BNji)B^2Rc_F?csZ zN~bi<3ui87g!36I2-+OY9QBz}SE|RHN^E_YOGBK*Q#1Jbm9RQBa7s#(zI?W~rSDoY z+6RXRj4}7e)|ETSi?Q7-dwI-aJka@$f061XLs4%GyCehtNy9?-idizL(yxDxWVm49 z9|X{-Pm>9>q+mo?KCu@yLo`AA#)xdI>CpV#CZs|ZRw}d2s#_e-I{bOtu2H|hm5x@E z+S+^NCD-6}oK2d}sIG36z`#k%@}i+OA8pRBT@N3U4R^0>NK)DoR*CN78Op8EKDon4 zf`Um)*~RhySH`qxfO`(eg?U6B*A$ShBPN;t$~-@ZZIBB*;)eQ~((I9)q&fF>izI#7 zIb}ydx*esB)|z|Q$;4><;Kr*7>PLN17IsCf#aoVsGq${OTib)U+WYQZ)^d7z+*I*kF|ZsJ|}&>{;!BsAw*L0>{cgnkwTYwnLqU~j(sJ8 zK-baoIIifN7!QQumFDNR`Z5ER6oKly%gXxXG--u2(8HR`pCWnqRNpFQ-H@dl+*)xMq!|;Ut59Qil4@` z5T(tXGH!-LszP`M6YLd;weY4DGiymItmeNWiWPv4-U&$yDA#w|`oIZcb%|~J?TS$; zr)wJ+CU|5ym9@oxjaXnTgvo*31*`K0QuEuEHWvvRvvyN^m?hM8ehD<;A8Qg1o5okL zY()c91Vcf~Ey($$jA;y@GW&2pb$?61+`1jb*&5ZEKgikDH|-N2sKX4;qi<494d_I( zXSH|o(K;deXv8$fIs)li`g&!8kB}R^B?VE>N+v1vI;|l9|ce=vp-u?a=*&U`K=+cS_o|3!P z-xlprXT*MAB#~)rNSeT3`5yjz;Yd(7;U_O&isB-K; zJXuYxP87c+<}F?Q@V!bF-m@cSgSngYsF_09r;%+ZeQ#10784f_xWq6I-dR&mzTK29 zyOg8xw@No9p|ws+NrE)Gz69sJ{2z4mO~-g2TM|@nA$`-11~Bj23C>LJ6-vf!u5ENr zhHKRGP;;x#Yr@kcZ@&70U(C@&!(9Z!y=UGgYuI((Zy&xDG**jpH@Bk>s+t_cwcgJwtdM| z^VxP~!RjVDnPnxnzX=QZ2J+%M)L@Q^FM=d+cz1rrsk_OI*!?-nsX&wLrYaq;c<@8W zjqLe6;dz6Bqo601IsX9c0b{PJlSNId@V0xQXuwJs<*ec1;^9IN$S*no?$5IyJ}nPC z-0mGb0Nt*g_kJ{ERR=R2)Woil1A-47H(?JUw+uCWt8mD1Hus5uH`RBlhchlc8{BJo z$&8WYBZwGT!;sr4{4c+e4#p1M{e|C#P{s@_a|(&D#t;&qxLWL&pCVT`9hY?7_yfr=pu-H&^02>BX1Z1 zcz)x!r1z{PeVcDWyKOU#MT8IQ5146e(~)%I&nL81hCkx3x(ZWPx4d>7znrSHUr3ME z-+B+2PxLVs>K9)pMt^+0D@`UA+{dy3tXPa~%HA9$e;~;p4%4t6#_qgRgq!LsJ?*{3 zOX%2=F0e+ruSd4JdVGRuL$qS*7}mifx@Nd(MO0;5+)&O)y3VA3zZl}|H*tMTyJEf8 zeuR+~=CKIt&TdI0V=@3AC77q%U;v{@?1$vD)`UK)U6?>`5w;{Y!gEi2bJ z{VQritn)T?qNxTpua)@2#-|-;7+I!rn};>GaS(2wi=`d)#XkqVm-C<7_bAp*YV|(! zU6s&Y3}J_TFFuGE>-`$uk}&ka2l=fGo1kA6mRt<+@$MMM zt)kE1!%2fw(M1&p#d*g$H942WlvSbSys8rPY}I;Wyd@*Z_dano-Rg=oIp&5N_$&M5 aYUPK@`ti!#h{gQ_LMGQ5w^2qL!v6rllKrRv delta 58013 zcmXV%V?dto-^R1;mTTE9d%2cvYuPPc*$ZpgURYeVjpdeYd+E9M`#*2*SJ!=>=U1QO z`1ZH*PuKAykVPXPgqz732O@+bK!zefg(5(QBEWy;E>iQt2RC?*fT>30$RfF84u?!-8?c6PhK5vrm*bU6C}~8`%iC= zc_2oTWiq44W#n}Hi{WRmy91ONY7J*Mnce*rKA0ki2XCmxLb!WC)=JVT8Rg5RH>R+_ za<@?Jj5UrWr9W66s;bY+jruGNZ?z2FFFEOZsoDea#zo&3@BJ*O!{M9qom^WCRivgq zS^o)4m5IRr2#tV6&p3DKnpVXP-*H$X*}?7v9|j};yZa%iCo8x$*XaWjNOzY?}m94iI~K91MxIEd1wPTe?e)Ae-g?#n96Ws zBIJnVeBs!H7`_?0#UP6Lm_PsS`U6wlUv_Fq7zS@7YE-QDZ&$7oa(^0(1~0sktSL_O z5Eop;X+ors4Ogf}ETp>G z5Y#N#iQaD82w3YEGx|XyWbEiOPtW<54&%&ri5tvn*GRKo#AluOHZ0#V>o^g|nIJnI zY)+sA*d@?=P-#iN2APQ}An@#So;omgQd|{ft?)W?j)+rg&FlvYhQa@={o{j{2vO5L z3qV}cZZJqR5jK3J&`{iY9653$!w}!wcXP3d%S~2pq@YPvCKlhbnCc4YDCU3p;I+Dj zyDL6O&Oxc1gF4WNYmbqZV>0SV_vOctRS-ol0t8Ayw-W`|bF#`Ngk8YkOzUY2U1XNB zShr&Pa^dm)QtN4;{a;Nq{qYnk(ceO=On{?ucA9z|POJZH)?*rrSZhI;_|!?ycHgu& z;hnVEqmKNNdzx<&cYRt)e}obDVOhNf>h_{VaH+;=xJ4uCO1T?{JXVsNHw3qfzoPU& z=VpB^EF$&(a3W$}ak~1L+<1j6CZT)AB{Yw5aH-;z)kc&Q%Hq&R8KoP+xk(stZ(s;k zS%il+OP#0@nZ@X0CjK!wwRC|@}uIkTIiQXhiF21oeZx&qaJ?IuO0pg2*%8b90*iB}?#;Lf1{Z#D zr{tKB;9&ifV6pLFD@}=kXo`8@%lafWpgES35~(h-jhN!bfGzcMCARw$E}WYm$Mky$ z_~?~h3G`1RAnPzuaFDWp0)Nwtb1#~HL+FeIabr5 zJ|&;GGPAAT{Up;L^>;dL?T}R7NFiT1mnZJUOQXbjl*2xTl4s&65riARUFGS^832kM(>rIi8kOZls7f>?@XLdY75?)ui0-&@WRH-VQlzTz9 z7Kjvtg$$PGngY3S*X;C+_19+JqLvb;GJ7lb%RB{$-=?g35%YzAfB2VgZZ~D({=Rcn ztU$hiO}V!syI;D#d&zcuZJQi%<6EF;dy&_DynKjH?-eW@y-ReQ!k%jN5h7-O&GjM5 zYgdBxN}D!kFgP*-9Df^4;Tli~zFZUZUY@F}p*(qJac;C#B+%MDy z0TTBbX7*&Bav2J=rSGM&Eyq*$++n%{) zEGY1H5=vr_wjttwb&d1!{oGljbZNh#3DjowV&`0B7E%E8AIwz7uE!P+@weDagPn_^ zJRw-r0y9j?m#a3s%5o6l-hv2339!*&-_9C<*UxEu7qtuWqI2%!{G88J3*Ik7IQtCD z;~Ak3y6@=>+i3|NgaF>01d{cuSAKUycDfhqzz0FQ?rUkhG*ecTzX}M?{VR-p4RTPO zEs9R+({jMFH#=kW?Vo1my-CHCZ|hUHLfn}S{KiF@L$tg)d6}!93zVQ9ZYPMwcPiA! zl^$PAw|!~jucq_NaG-iSrlQf-&FPCGyqwg zQxa2(fq}pW$8L}q8&1#Av&Te$0GbH5Zu+X@LW-!~Ga~3q2beEuQ5`x zx;wzxX#~c}#@L4gN|_7YW2izTMogR3F8E+;3u`-9pV;Z?;@NHDmV) zjrKMK+6J!r{(^rSSo{iRsgD(fuH6B4!v4U-aI=D_!bZG+bN{1n8_YWr5mVHX(ebCM zJ|=(v*KFa!iS$PW&BIA6UHPT8B7ARlq8J13KW@VQVfN(G?$}R}B`sQRtnB=+@@j0Q z$jO|=^GO6Mgyoxh1$_~sBfh(1QLU|GT}AuekVNwCbva^G7;e}?;C(^nWgrJQoB_&H zUv)o^{;&@S=?D~S!Ed}it(C{ux!cgUR?+usxW3hqzN-jw%^n1l@6TkD&r7Fygn0E^ z1lI*Ku7r$M9I`y4Z@8<1`73+OvTS?X@y|D_(VxT?@gK02+dSWX>WTIO6Sdz{FQ0|& z@0@sk+y>x3{)u>iYt7Z&DX%TH+XWs-L}L}1ld)k^q&IC5i(uOR&QnySXLNU2XiBdS zc^Vg-B?>X=fip|V)?|GoY|!@(vMTeZAz-Uj{#~I@ZU{I(s}2C1^na39jNKo^hCv2sEe|Noz6gh|L26L z;Ii8mbpGK-sYKE-AAfR#jvTj_?5TB6@3L#!hGU|e4-U`2KO9}(SMj^f{)_YP5(zy+ zXlsvVFi%Lw)eMS-(_F8)TN>}?E#FU6Zv{W6+p*PGZF{~f9u^z}W*T1zApfXcyS6k# z#1URe);5r}VZ4Jq5Z3CS74<#j&*3wgG?aO@J`(d;NqLAs9bgf)m$vZ_Yo8!n`7aUQ zlW1v@)tx6(tXIYVzIRWsSu#2x-WOLHYrW|B((+yS5zc$)-Y1O_a$Pv&0qKEzM|uB# zF55AnDx+$W4gxsohU((IlxTdvz zSYWD|zL=5q*`RhyuFgg7UCEU|pZ}w{lUJZ$qM(-CArIfjqX}V%eq@o7Pw+jPxL5@D z{nl7ftW<3f?}icb{<63%9im|w(naLrtgzLiS6Ectw%cYPu2c>sI1nkb&NUcH`EUvPi&}U0m zm3ZTS{fE}CER9FP`Ass7i6QY3V^*jQ5eLP_i4TK5)D##~`1`My9M)G)&XE-gjq5IH z_L+mHy#;(YH)0|t!R$CYvE3g(I)we4Ck>MR_rh^dAbzhIR~xf(J$dA9v_i_fdZXVM zGLa4u5h%mfX6)fmn5LQuEvr>Ua>msvNxg<(Yk2iHFOn9m=nyHeG$x7r);8@M zd@iS@Gotdp10Lq_zC2eX@r(IxZwWycmoqbd?c4T_P+qKNI}QJ1@1%5Lh5FE>MaLh2 zxX%NX#NTAAru*S4PtxldMenB|Oq@EHgTG577yL5tyEMKfnT^#8^Mc;FMpayRW;Spb zdRipzIV8x~B|3myX|(H@7Hw)5o7K+9DKl8lZ^D4^%$giAZQhOg@|D+crz7ZHZFGLM zz#y_-2v$C|oFgf@Gx$O5DmD+gvco{t0cTyId9r#+hjfTw0JS9DfE`;y;h!5J|1g69 zt3L6;Ra@f3qX zOfwC#j+=x(f=K?Ts@(vCCm^r$2q0<{_0@{L*-WU| z(EpzC=WAcvCwSt!Q^Y3zt`6Qb({(kDViQq47=J~p*qF_)SWo$R5XKf)r>0%^!PSpnW&U_( z33-+sPPyC-a~~i-w7c91O?_R5>LQ8ERG={a5(cduWfW8}kuB0N#2J+^()kU77OhW~mV^P2GtXxSOfKdfuMl>JpS`qk!;=EMU z;(=rl)tSYs4@@O5?6{JM4tKZwL3{R82iBu|_IcWBT;t2Bzmm#qXg_zOQue`_S#5kF zS(b>?1mlHC#un{1)8CrSBgLQhW$ldt)vsHllZPHQ=m@4e)}r%@+1vEaEUEL@W}$I< zU9+gu;#IT{&}N+RuzBgvEVqBWCXB)qCzrZenQ#yTvvI4*^~l;#Yq&Xb*$k}Sf)*vc zx+O6CX}9Vk+-`BTE2n7-qDB-7Rh5g$`QLXY#>n^i$W9FN9E9AymdYA>tN>YdzVJbCgDI_ zw+V9%D;cNtA}{KOAWLAU$X`miabKYNrZfKT*|X(~qWea?f=dUEt@|K4HQVfMKw`xj zGSS!vp-C@U4^FX=h0i+0BDJ?YQe_*rlE~x{G`EarXb1xs7)?*}b^S{VcJ&kI+*bIX z_RVwwySHB|BBnjh@@ytB$Rw>QQ|$pEEMh2*1Ptt(2(a&EqGG@s)Dfi&4zZCK3RxM! zH=8CVz2Y+qaw2R`VgPGV8oPEa%_nYremS$M2A5V z!k!-}ja^9zaQ@n{X~@5#DD;ESf#DsdpgQnhSV3(B%EE02n!v4dz&&g5Lh6MltXJ_^ z@Z$$c*#??F;qBw$S+=n2|7L?_i1XFXkJ7&Av3+TpXV10=uf6calA!b&DhIXLGF1e5fqbzGz@Nb) zQ^iHywmj`#WD2A@piONO%$8~C{`_F}mXCRhna@e&dbkOeSL8D>84Gv|bm@Y?WJr|K2EhyY$Va>X5Ul&#xTof6*nFxw zUt-MW4e1dsV`ZgPY*`sR_tTOhSn&A5+|{XS;;=3JH;j65QRjwaT(+kyXqD;9O$>VR z4Q`9_z9$(>Yx}Vxf}m^dGe#e_kSTc9DzB5phCYS|vWKNT;FsXjp zn1n1*r!4~~(|JSCF-vw2dss&g5j`|~`brw4gC`FdudxbEVHO4goUo+weR9_ilQ}!8 zzjVy4L^PL#BPVAsfxz|<)M8EN=dIW*o4*|#fs@<*7=g>F8Ll>EOA}Vaio6<$i20kG zcU*|RWQgXjcsdP*zOVJ>GiC3GBkub9vq#~~-q<~vCV;W=>ZDQHFBAVb5HF00w}avl zSG?Xwf>!d%1-A|g@#ZDV>xy7cJFMgVr`brPfd%)Qc*oy>5=KgPbp4GVMNpCP1O)t1x4O?V2CO++v3vNL&@2AM$s3H?P5loA1^bhd2Tu|)1;^=lj#gJKpa>h_hEoqMFjzkA>hR8~4r$hUE4jC~ zrrOJL`ynrRATN>HS!oYIGM;{2!RYMZ8m}SKF^_U4rt_MIm`?`ly9c-L?fb=*mPFC9 zvTo!&QlSDD&Gh9AC7{#8|LsZ3)COQ333meywGUbX*e!!gA9t1dFMkrIu6yLhm(gEg zY1F7dTo{3U@eKvBp=38T3FQVY_D2#dEDA=A8#VsXiH10m=3!?HI54E;UI`S6z&D9> zfJFKOBr2(Fa9^OeyE6m*VBADd#GrT~4nL(;y4ahrX6*QyKRB+^Pei+~iO$go0Usqi zTCV#?2OOC{4s652K=)Y#qipaIn3TypvFZ>tt%pLed-zS4lGx_fzLA+p^Y^)^7XncT zZ#6Q&&gsvpb16Gsmg8kCEUf-M;V8dQ(^rdBBi;VkZA7gM$Sr@9Y0a|z{r&Sp@uP}5 zExE3Ba2l-p$8pJ{6tO^nC<_4FzdIwctHF;ZU`K*M(>`}FNC#6^oX{pR{w)i0}8vvB@Si;Q=Houh5^s zoHtsi6eQtOcA=*@!4Pn^y0wDpV-ToXG9aC^;k`v|h_?=h*^V+*;*D`=>_(+}d1$x3nQkRt@}lK2 zrD|$Rd+1(-fi0@jdrSpi#NO!G)im%^<&Iy3E3Y4;RBZIqn{?Wyu9u97RRw~I$&&ox z2pIiqv=k8c|GQnLJ-=km|bF z@;GkOD{O3jM<^Cy!m`#2Nzwci3DpDX^-&CC^Hr}gAf%S=t4R_9FX@Rl-d4AH0=-vYFlve~!YH_J=xuoYwc2mf+85$-0Kw(A)_1j_h8pYQLdqI3p zD_`)`Ysdx|V!tN1?1%H@kWZw@NHrD%<7wz-T>W7`jLJyF-+3>Z^~#D1<(JWQj|=xZ zmN96|nFsZG{rFQ3pWtGvLETj+M2(^{5`a2bltvyw>s|Jb83>|p9ACq^-k!?0S;X_0 z+pbSwoPTom$*{#VO{x?m=}4?xNA6-=%A44?Q=l-lEMQ7i-Y6HdY#^qQb`TFl6O;`t98eLHtl-Sc zA$q|alcNg82nTN-UzX8a>(D$Vh^NFQx`8CG&@mkDj|w~E?X;_~k^W0C-Hyd&PKDb% ztD+^DryjAFuD|};jc_(}>w zv$_s%a#k09wzgZ^flmaAK1I7`4M*Csbsj$rX_3jtw)ZoQyO5?GzK#xj|CGBqdm-rFc0}?iw#rm} zcI{=UVl%*;>NkJ}VHh6!?wP&`YpJ98Dpk>Rhx;Yek)M7}mg=iHrKZi!|3;Q()czYx z%U)-C8idG5(lRhz%P>Lynv;REE$_CgwjkzyFS53to}_0l#}&xPd{>sm+AxfEy7 zl1|jR29@%b8#eac=LTw=bolqgLe=u?$dvpv^r`6FxKB{K< zEPIqX+RCPY0ZLWmlUA5Ix{xOp!EZb4Lx%c`S~Ut=0%=kr`6Q>ldAxl1AOB!nw4bOg zG62x&OQBX9p-D6lU3dSxVKpiQv*vFaUyjc=6!>$1%Z_AV=7Q_9Z(t*+*d zA3T=FqLxsho|}O=a|CM%lEp*F>6p>k2i>v68<76mq^Gi(6#U=V7_PY|FnSeLdGD5- zMpEMr>5#CKCLgLQ3XpDZ3JYo8-4t4JpFcfYq@@ z^2^xXg!|u|6_c8kyMYBI3?lijtiZS8%UvsN>2L{gL|qm9bJ0bDCvslWkFrFpxTXG5 zi4qmr{E7o?ztt~S#-^_(9!7$OuI$(*@@5j*?m`hH(f<(?2?9tA6HWrkli-81IP6b( ztxeAIh2W);;8>INF$i;nDeS`AwK`n{9T9-u!1ktn7?pWK}IwRM6*uF2&j9C*u znvzC7_gkF)B{l6u^oEiAZ$5p7H{mCZJ@{gE!wlVJl(BV2)|@^JG*NYDeR(uIJoVqP zWEue2E3`WO1paTlVc!{7d4H#|;t3G8mOU|hjoRSZ7hGw+o3HwQ zS@{WP@t>AWQ%|y05EVJ}V|py1j5BOOUOOp_30p&pU!tgDcCZ|re8pdgac7^#A2X9P zgf1AP-S@_l`#pd)T@4|!C$NW`!#w7ei2DcsZ}1_npbNUMpnWzwp0@i`Vf6AlqjxzL zFgM&K0>CL+GVpW#DG`=kG)%brGc3Hq@Yfo0gOEEkh3~%f+ts77sBjw2T;g~f3{fK zWS0BVgii0`yeVCKOvF8FCQiSs@nmEC*=U^K4;k%lH(=m~*$wj@5?XkkV_=H0l=P^U zzsaDeFb3Oe>$QGCBDmeWoWGN&|Y2 z>2l=>KKXpGeGHArOgi#nXG9MAgEKHs7U(pQJEQ zPnE7$iuw*2U+IYK+L8l}4$kHV2_C?3Uqt>czV1Fyut8ud`#m@s<=Ok{PpOYXXR8P6tF zoU56>mZ6=>UE%F#3QmV$vGW-r$Ur|x>YjYG5c1plhHeP)wYsV#vSPKZw6ffDOn$((V!{8)#joJjo%V2OZJQW;7@>vE^KI4rdZilMaOO!ObR$RKzMZ!)z zo*MUPlbg~-_Ud{OieRq6X(2=5?z>GBltzwVt~7#*TU{2b)}2fUnT!y=DmLcKHFhug~8nYU@r5 zTwBe;SnAw6TrB%n4d!2yw^|Lm!mwlRqO!}ux~t3v^-DP#&Nfez(0|nWqOfJ#@Eg&F zZusBDLWeA8A%o0?Cay}zwbr8j&kF?iFg`BNuE|B^H&*^Re-KB4oONc?+R~Ug`XkFt zg`c9k0FKAWMHtK1_cpaD-2sFNb<;?On3p&eEL2ns+rRDu`xY&FWrI1&68aFz+6DrG zD3(v{;_k9HWZBY+Q<#&gRS7*oIm35Oc%217un$g6auyHacCJVB24PMKrq_rx_o|1e z;wp&HwDsb6CbH(-Aom`UuWCe3W{A>8^e?9=>XJ zQ;>VOS$=d`o)iDTe#YJOUuQd}H}fHDy;kU}@>=VueY!1W`LTZV2{=0>kf71r(rJaB zKwV8@SZn!h<25N}t1Oh%O++hO;QyWyvE?P))rdZZS zu;8IDtu#+z7oP0#<;-|>=tnUy89yk(pYI&s2c4^WRJwV+YM<=dzIVJ(`(gL}3B4c(kwViQl(JD& z3Dv|WEf}1)A+2(&{ri;_pkizB9&CHEzk3+R(OU&%;It+a6=#LG^vE?AM1n$@?RP1Q z6{KTk9p_1V9YMlb*Mdc>VD>GdD*N<<8t~tQJv<{Q3lgCYd=o?Mu;}wt{pc-6N5Rvp|V|B?H824ykrf2=*XX?PN@#MUoo`tT*Gq~(W>l> zNjH0u5nHgpgFOoI_;c@gbs^_GAM`X| zit-RpG0@(EgRBfK9LT4aFnh9_%!QMA0u3BxKAMb~)GWKFla zb6>1zrhK2Xks%gp6o=Nf<6|u~tM%14?z=ZH2Mo|Qws$4H;j-=HP^d{yGw@>=T1{;X zAvg6o6MO7t+mKqd{-#iVxQ+aspKD}AlJ_IC#ZQ5#t%;@Yze@F*{pm0K7g=~7E41+} zY%PFWvvsTB(%P$i8wN)3jiP8@tS?HQM zsiPz883_DABm9Qy9SGd-$n3|t4f2E=6XDR=xh>g3@X8oYE%gtb8`ki7@TgE~Erd!0k`E#+ zGs)($zVIyHzQfre8ns4Hp6?SLB)9Em&Q0PA$* z_lkFDsb9wP{sBa+3Z|1=h%;PJZ(6tZvKE8LWj&l`)*Pk@Nvnrr`RIufMcdtSFb zmYaJF49LsOGba|*wsuzY1v}TI zf_nj-d9ZU-Q1V(vjtSyxWHwL=mXwS0rWPypmoyQNNTg$; z{gL~FR+r}flFnP$8+xwT4t74<7>A#MA8mVy zXk>fBwxjCmVL~LRox6UYkp??n4E@gKo8!T4RQDx!vY?Ni=eBj1(aL< zX-N7J`sf&N4)Xlt)#2UT|5F7ajy69w&$6iyB}v-jOh+1&$*OneuX zi9#&X8kN-E{$L6jUC3Wj_RMYA4*T+$ZM^Y!S9@Q{e7zB^bJ+ z`?O;qmm+Ihe+GxlY=2`-N=7-)4*Wx#ANZypp;xa_u{5ty1%t=`s*QeO6Q<+g83+bZ zSC4<)SXXV)OOk%D%n8BlqBf0L(bsmlQ9hNVx$>l}1oY(2G>biWm4mv?CV6`S92s|P zpS*HA?HN8054{^K&EBxNbK3f(JO3jQHVycZ#Gp%!obFR1#1p&Z6oeR@PYX&qP;j}hHPgCvVn*!7SLyc3T&A& zy*|wS*}F%!O0XDZxZ-xScc@8evSZ_Fe8x=QOU^MNgwf=Wd=}N=;gDPC!JMtVuMAb6 zk}GP{+40QKvZ~kdCr8o;wReKWPxoRNDF4Hx#v9H_sP{YY&-)OMf$fdqPpOk=pNQX+ zgNl^CC8IMp#TY8V^_$^2IzX$}LCdodly&r+Y;PO#iV(#xL$>6d2N%Fb*?o-63vm;V z0g>I00rNlUP|L;bYCxb>o1bjP^vQ~dO?zgf;hEh@ntY(?1AwAu9)%gJF}{TnBBacA z_-ndy$C4|SrsF+Qg$a`RH_(9Nxg_rIA$wi%hgP$n6OsOG${YBkghiKXN_fbQDxs1; zrbATEQ|pPB6$tBzOb(R!GC~aM;tL%N5)k( zF1L!~EE#hh0yWUS0U0vI-kJaWZtt{chvCb!5 zoi#}N8Kzcu6Wo3^JW?qw*_UECJvnm{Mm!BkOp^X4)%7m?11RtabgC{lr{XdVed>^V zdSIbJ8V=ib;q6t<{%=+ayP^~gm3AA!C4D0%2b!xqOV-Gm=L@8ZdCwclb;2uzjZ)@l z4LZqoQbaN*mtq}XzkI|tf7cGHq1XX8 zoH;+h8S@X45zcr##FkQOLJR8A`%0r-Y%HLk;X!Wy?d1=+Z`Q_}_*B%ql+`PZNTkRH z1pZHcg834F=JeZ%WW!~dwC&^7J>0g>t7i)hdJ1>ABhUDwUz)vTw4&W)M=Jy1m8HM#|jnJ)ab}7<*`<|4G>H`F- z($u7p$NEKc#eM?5|BTBo_LP@q+^I)9sXv$gr(*1c(Tz5DaAk;SU-qMAX!kqjz#py& z5coeOv*Hsbs2;7@(eUGFWt{l3WY-o&91uqBDE9%%v<}Iqxr5HYdhMf}T71nyffn8U zjd$0rrOWG31J9>Xsznyp%4wIn=n}p5?N9S# zLY3y^#CdZ~6^t~10CqE5SG1c46DYpa_R7XZ=|get1t)*lgFG6xKBLiC#tJex7Df4g zO4(s?oR}m|e9Hro(xrsbKbe7v0OBAmxO*|p=(NRxiPxOla9!qNOY=MBg7qKv^|=j? zAKeISZ-Kc83)LvSDECE;*9M4{CWHeT=_&6D;TgNXyaAB0H-cJ=T?^vX{`MyV0%TD+ zI?W7nQBx;fJ^Yj5_M!xymHoyb4|SOgv9vBci{@$)bhYlzf*b~%ORqZx>B z*xcKhrd>2audyDk`eqvBrYct=d` ztTa6^?(ui6bEe<5Ogz}`+jS?-wUB%1T31Uzr42F!`>3g28RVw_TW~51-}2*~#dhQL zN^((i!=?!oGEwXA*DMEO?&4_W68VbSzEuIhitsXj_|ayO>}wQ;3L9eoC7;4F6OHXx zamx>S1W#sy5~6e@F`Fi=FSUQVdb3o$2}&~;%`jwRa}$&)WgUb1(Zonn-h(ku=9nEp zXUOqF8Z~a2HcoOCibvGjz~Kxg3vKa1GY32&1CRzyZ903Q5JG?rrO)^?(U0nFQ{Ylm z{Y7kj-4nF=4{rJtx(9~C5z676BjOaF$RA!k!!OMvU>W|u&vZdlOq6t^--nmHZ@e!J z2?OpGMt!;FZJrq;x2>X43xc5F%jKLlRIf1A)PUs^(JP8;$*%xR@E%qwNf$azN==v zzyuS8GLv^9cop3p+grAlG;1s;Pk@vX!LQk&dm24U#-CdMybgIgJiBekI(1dZIE;4( z>)68_cTBq@!B24nO5qv&cSr37TmCk0s890*Sg(5I5-fTK!Bd@0OE(X6jP?GGp+tf@kr(yz^yfzw7T8_T0 zAreRL;?<81D6c9Fip=`)wnKElzIARw>jZrA)}rAgFD6*9X$6>f_qE-Et#a zRRN6S^j@2#pue$lird-vD0sx=%C0)B!# z0jKGQSR2a&`q7|4>pAuy%OF<_F+{$YN-cQsQFA$Zu&*(6PR1;t_k-RnIX+V#wBOMG z)(>_cAzTOmHiuMUsP znh@scx3W4ZjSt?uvTDCE#QUB7MZnlXU=5+_hkLj@)>jP2+|B6b)Fjy7naifH`UTdu zlMgZ9z*d z8U(~Wj*wSI7lfb=;NzXa__}s?Y_$aa>+1-(Zy;8^+ttqJpDf}fL{Wu-U;8vCUBnOQ zCY~6!zXG>*eZ(T&N4m%!dyO(#t8wAnDp@O8E1f(owt)!#+6W0bco5NuF^E^T9)vYS;(E%l&T>QaB3aEioc zRh5i>3MQ3Jo;obdle~BUb)c;5miX#}U4J<2fArn$0Gc8AMQtDJ`HJ!Vs{wZNYiVx~ znC24l+F2xmveDqn8V*V&9s;vZeJ^V-^#Wx^p%RF$1RaMc%T0AwcrFTLvyI*MyxA60 zjc0`lK^ft*u&RWjzH&6cl$R zn^T1wj#on2_0Yx(vb6HlngG-X3dXtXT)LgWHW73t+zhl4vOY{Ac`lc}r|QdT2WqN6>a+dL?BNGctivnx%` z*vvE_rIwzV z`GtSk&NQO`9nk9au=^&C(e0gJ)6z?y<nk91L!F7I#-0MijviZO) z+EW|%!853-#KU?|IB3)tgC*L4^+bNM2Q;MP{5W3U|5U&psKasDm$k-; zijxYY&fz(AXF6I<2r>f%G!tg%b=|ytWho7a_QpCz-|3K)JL!FB^S*cS7l2OHqnOzx zZ}}0qEMI$WGY%9Gknn8aI&NmZ~Jkl%w1FmE@elOH&#HBk5Xz+`4*rGH1=-flt4 zMZ)a^j*T>qJK~=kJUR}29YGf0(w;Q;8vrfORLe_4Z+HLnaDzI~o9Z>(n!XA#-~03L z0CQKCpwPKZg0SGX`YdGAU-km4Xe^_9iab{$YB(VZl_B0_Mxq;0IWt__hY>==i;1(6 zSE|;$yb-xc#W&dH;m?X=*5QVwba&$1sqfUm#VdTH;0Fz&fJPA4Fpj#PQbz-%&8G9~ zRI2TTxZ+zr;oJvtT(GT1pYkJ*{~vqslT?vA6F2+v>YExIEW_i9jnWDXiauexn>@pG-E@pSgj2Sx`Bwsc~U5zDobRFWIaBI;4v+E zqrquY@|84=sP$rq66i~%>@+$ntSkvFDBKZ&!9FCQx6IOZ0AL8d^?C=Ed6` zppUi+W@&dIFa`g}w7(47AJKL>0d~dolPRIkw1R!!CuM~4Q0#wZe$XV=t8$4XE*u)D z2)oHcII-_i()2oirbXC`%&q`g2OBHQm%E;BL7&+|Jvc9DVDC2~#+u6Pn&JMa1?@@+ zb7#`o6!Jy+!n$yE``Z?E6Mp%V9iLK4{W&kh^Y!XPn!6q5(T=TdHGe%bd3a=ws|}py z%?IwWGJHkK8qYWp|C!ePmY%qbUk#S?oH3w7R?T(<0AlAG_T5^t7`9~6scefg_t*YjyRl43|spF95C|LhHu4gVTE zS9PtU!_;Wc??_HSiXupMp2&-ONv;>7scWp!%cToESE2rOab?1&8QNYyi5vK-+lOr= z?==veuj3RrXRy#=XC*SKqGHJFpUn8qDq}Mj* zYVSxBj?6hO-=lhQG5Lb4mq~UmmDOKZKUU~Gebe2ci9n@I-KO=f{?`!nVqjdL!XrOu zas%ruEYE*zzvY}xM+1(d`tX0j#|%nrm_o zT=^&~<;a+%A8~VcoT46}ii0OnWGhv=2>{!J-Y*2AEiv#^2E~?Z96dwh_wjam~0^GkwkR(6V9i_a5QHgK`&~8Mc6T z!6*0jj&*%~UcM0$$v7Xz$U7>OL_32>4SM zkhqG)ooPIfbFldjokK#40%{G$)x~x~#$6vdUezr~!jp?XptX&06WP1NgI+;;hufQx zcR@l1R)+ngew*ET-c8pojhB&OfaI{hP#EAyimxO4y)AQjLoLiyY{z|1%`zI}Df+v9 zy&wcu-{OguCYoblf2UdRGhCv?^nu)Igo&!A?z&~f&!$#0AyoeYV2$7?=JBg9S8z-G zR2;YwJGlI-g8<~2xiYx8n@xnj8{`GeQ;VH;7Vx!tZu39k#!!=;qi#;Ov8}q&_qdE# zvA(dO2TtW3{8Ki<(AWd~(9s7v2IV^~zVJf4k!qotF7tgcsNgxw;-+=t`D&Lb?8yIX zRptSx3KV<%>t_P=gddsj*V$N!iCmS|tkj3`LL7P7rb2(w2!rEBX+xS_> zkZVq9sFVzSy71vsQ3sZQ0@sccb@m$}jjU<9LVsy*)<}SMC}uitM7uOD`}%R~h>SBd z??FkE{}_LMm?NW6YaCJEx%(3T5TTFBj)KH;-I}j|D&AWBoekbcKWTDjNsm9~Kq2=>tyDXkY8M;AJy%e1d^{L! zhJ|BuVgU%?)|^zq+UDVc?%d}v?Dw1g^B4olf#n~!n3&HaFe?Q^q#(_Cq`+lC`xOaGa(PeRu!MeS>8X|Xlt9(p<;O~4FX55;8WTx}9S{&y-_1EHaL7L z8-+l~Pg&E=4py{TEb`b57+ZzF19vYktdh=3l6jS=X9v$}_S0GqDSQx(tVEq&5U0PO z*~!DYAyKaT*^lH=dhzmhDM$FX&UPuKvT;8PaXl3zJY}^M_fw|3Y*kSgMX-#^F2$3D z*|B+)#Tc^H&dBXh;oe-+|3A^2{+a6exHO8bjaQ9wtC8+7kw$?YY5uK-wzt0_H2QU+2JD{2;6PTC&EjWP+g<$oH%sTfPi;uD6l=f9CILW+^d31s$AyUD-W3Xv@uO(Ou36uwTE1WXX!?jE zXo42phWhQUKXs^rR{XM@Y=CL{<}NG^S;+TC)EAYj=WFooU3@x!ULtZJcWuP?mMk)g@_P#AHCVegZ*%8_5y zDn9%DReQLoN?yCucp%YfX8=?G2>LSr$F7$M728|@Wd-KQV+FwnaFAgBQa4eu;Zj~_ zBLsCXDKer|;O|;^e^&0dOumaoPZnR-asA_ym!eX$>63K*Cr&gXD-N{lAi!BCS7D-vZYiL>TobcP#;2cYk;A z>`^k#9quR)(j->0zsD_tK>3uSG`#E{h?8h4Se)P@tKhkNhyOPjAK>|Oc#DYxN)4Nz z+5blQB@U~-+;d&c;dl1#!Tyqbc8x#W1i`{DRo5Dz8!!}KeAHvsOazr~ZGN@(*U7I4 zzPJ6V?79N<*?DS=lH0;uraiFwPY6(Y`d2b(Y z%GU@$fvB?BiRzByyVKdwvY_hv{^8nXFNYVc{i-ufq&RCkfoejIj(}npT`fVBu(T!V z23k_hshh@mOc)+7!pFN6Rrv>4_C9Y2GS z(AJxIbu6x)0S8nyb$}A66Atx?Xc{%!+CMWDa_pdJ)b5}_|Jn?D_{APx+up(;1abASt`&EIs=#@Nbik8Wxl!N`DSqk6-k4GbUbSA8Z;Z zPfIl~H0ol(hK>P~z<@eIN1i&wm}*@t$Yr7|`V>r>QsB(mqEV9V^%7=-)xK0aug+LQzbk&|zIhD%)j1D? z8xi;UwuQ0?Bs6kN2?qNCAYF+0f2X?2J$E!`btB7F)m+is)fHW|4*5{@2JUu#ej#qL zsOt-aek5jC1O|5rS02daz&{EZH5H`C0v+MVvvNL;voo)k0%i?xo<5Nz1_%mu{v*?% z6Q)U@&FpKz1o<=GBcU$%w0rAT)QRHHeA$zJ1XYfTeAlnEV%X&W?e>%aNa6u{SWAio zi$1Lwgz@Lq{uxPtw#51s0g2D=ryt5!%W2Gx>^y``-$;8*d~(cW!2!z{i|x-!C(VV> zf7oa4`*}dvX0VD1_2+BJ6bsGs;q&&@q2GCWMHKLh!s3qWploNzY~6RDZbRa3%4a!0 zf{NnV=F-BR8>M%|u^Z^|B5CQy1wLaqh6(B>iI)REAWy%Gtv6stQAweM?J5-RSD&oy zWIbxIWKU2W$RHQ{vtIJ7rUyZztxyTquTZPmuJ8|j7jx=W{+^^6FkACW-sw?gm72hlBZ;|+>9@0-N zoGsp-Jmbo3>!ok<31Z`3>SQs+dzu3=Vm@2xPV2RwgV+jEqix`w>STXo_p|YW0(80^ zel&|Y7mF59pYu_C>>l6oxJ-8e0>+NIsVoF&IJ76X;*Nj0mN276P1k-7M28@3_#sh6 z(9rhE#F|PM!LZ=_C8#hKv2ZNIefaR35-wkd6pGn=*$wEy7axAkBOA`S${?D0O3JGO zWxM{kDL34Vwc_Kb{m<8U2(H0qoBXHNCi??dhm&3 z+*p|KuHtP{G=fJ2Dqe(MMyvBrMtS+|&(fzc2t}RT9?;OKH~L*JM2Vr<4tRI0Y7Fr6=sb~ zWbptpv7j!@&s;j7wsO@)JHS*X;jnme?gRS^NVkXmAfIxHCXQq(_xSfxmUj@U!r$X3 z7l^Nm*YJqWzXd#`R1|u0j(zA?d;Xo14Zjg!F{241>YGP7xHKm(IdWKY$r;UEz!Gff zYNPVZyuw+SNS}p?C3SKFhjmdGvDkuL{$=&~4LW30K$5=4KIUO%0tcA>{g4=Vf-&dF zJ!Uu5e~M(s-yP~QNEIVf?y=O~^=@l;1i@B$bMzknjXbz}sHb-sBDv&cPfiuKS&GSQ zj#OR@1#(f2Pc|-nL0+Lz%-y{R#`x2zzVk9|QZv@Gw0Mrcf*pY8OquA(A_OVG?72o6 zkft+5u{#X>gMXL}Q)abOV41;x1 z7a;lO9#(AC$kdiyG!qY^tXnHLBAac$FY}V;{pJc6O)NNwSn@eq*gUrSqq*mnRui6o z#YFc9^ygwwXRoGO-PXo_rWV|1+cx?Y_wqE36us2!Cm-JubX#{=RL@$$sfm-zy_Yu1xABoN>=e_>l_`wWi{ zPx+fbrK5HtmS4u+qT=i-8+aq7(=eLE&*Gnp zg!wLrtxp`S=*F|c39G0mKy?H@<0G^Ni_5D>c%hG_*_Z7YE1J6(12MKo$%x68Vi($h zsYy+WR$^qJMoI+D8VdOa(X9$~ZoS_-3{ouA0-JA#ECdy>VgVqI%Zsk4tXC7FPsp97 zI;EL)(b2M`A@)VzW~SB!b(n&TUv$UUQ!_*SI`cIWS4|xBtpAj!k+5O6eEwt4=zcTy zNnie$g#0YXKa#?cwZ9E?*pj9#`{nXu>N#NtlRNk#%Ir>q0Ll(8P$5B`Bm zM>1TjvhIW$ZUsJRnm$gnhDv>M_|B?lJ#41+e-IscngABnqK#)-hQx(}*6wknAArlT zQBhOBf20+B2J5E$yy09 zp_X}T?rhOK;c&o?4<1niNC+BrWjL0@(wF5;dU+_8)APdqJYQ_>gDHszOZ^#EA?R?U z73wcgUG2007my+UbpmE$#t_FhC=gQD=Px6J9Ld=Ul(*b^JEM={y+?*!C1KClz;RPa zC^!P6B$a3T#~++f(08<`^XqRh(l2ET!^aBONL}Jn zjtiNrRG{aTk>6fmmJt~xhxY+FIc0F~!$S*PYCc&xE{5*#pkXUzpWAB-Sj<_r6g~ihJ0AfCf*eQ@>(T3ai#<%hcO=5mK^qI_8 zow2O}@JlQ3BUS@_mUbe{^}v3ipK!oY>ccPJJA2%y9=ROwCmdo6{!^jufi@kWQw!6C zKuj467JkW`GO;Q-gqenl*=R_oKglMXQ3_a=Kgc@O9&#r2{BQ#k6eqEnr8>vLBuL9v zi&4bVcnErjuoQR|8A5dOPISM&g1a7I$$LmJSGq{eCh2olw%L(=y_UWGXF!t5gfwUy z_a4Zly-Jw%mZg?!AUz}ZyY+Se)F1}IwdOnzkin3|tRdJiy>Uk85EFcw_ zP8>r0F7ZMLiJ*X?wdN3SB7>{LgmjxiyNZ1mfoc3B79i`my7M-1-8YRHdjAXyx;ae- zW(1v}W0^gtrX9SL8tAcX$!#nzVmNG=*G}3_RETO(buAf_(;4b2Hdb%BBiBel5W3`` zFe@56jcvZi3mNSk)Xm635|>lIm#;!WP|Noo%s{|RtFMLkTtB6F35p-#6_eB=5S0Fo zrq8l39$4Cz$BV{vtW}QZ;^hS5i$bCbc@%jcLorV8LE^gK`?H;AyRI>Bu^Lzvql+WQ%lguc_xWCtEV0K2N z6~L`B&M1PvUhB0@SSH+yAZx+-I~m9kJF4kh?22EIG63{2(Uai7U!afuCD%+{1B}EK z`Du1gWdT8;IQThi)cxqbP~0PUppf5rvk7lW!9w^9?%ExILv{Q-PX#@5$*oB+9<82c9fqkq@ zlIccDe?ZJ5R0Z8m*NN}W4el|u&;?)`XPf`%*_RRD6wfbZ4L}OkP8rEC{6oE@B{+74 z&YrB=Lt z7i<#{U)#T)tq4NW`KE=Hl;l+u6Hv+?dF6a{oO&b@Q0-J>9Nf#{(N}KZ@VyR1EmvC>vTmW=4(Ww zQ-}K%l(*BTp-Q*%n_GA9O2xN*p7HCz?LaQm2S9P~HAaQNry>Lr2vVJ#* zW|vjE$t7*b2e8!^Kt<>XPGe~Qa1Q+n)zb~Cez%XTj%<jn9t8MKVI1Nlkn14evok{WmZj{ozt~V>IGFh>LnO#YQPHv)Dq_n z-TYKec|~y;ut;Lx(E$s}^V^NaIDz!QzeCx`PY_6U+x6+DzfYeUnUdDZ;5QMxb3rN2 zj59K?)UqQ0KA^Y*l~?8c@9JSfG^lrVs;8us)koaJ4D@-?c2uq}deL^8Yy2QVK0ke% z@t`IwZN6%Pb$@qVJ(wrk+K8WyLqfX?YaEnOb`0f}-u^m9U*sr~_JL=Le+?tKbHl_0OB#C{_-Np%-*T-Kb zh;f!XSAPGRd6IP0VIl7>*62AqELk09*!*23+P(6m&!BQ@HLpxexXb2I zGn1-ib{_K2#mtLOZ(S_-!U6^X4#zGxZz|!a@*xSLIB=-STYJt|)%^z_7Km;PJSh0> zx=+P0BD-ZMzr#@Wq{c?P6Qwu-URfA{-oASEZC?^E91x^?<+suPnPu?tQ`_$XBC(gm zu&e+}A%viJ#()fnMnGO-yR@z9%N6V%Jy2lQIIB>QTK_LOba=2u47^PS-M5FK5ONx1 zkve{!jsR(Z@B6F8wp4S!J+nC@w!2Mn4^h}i5IdT7bq|!3`OKq0U8ZMV@(o4gZ#AN_eYeR@f^XKie+@z3i| zSx5RI=Qdtcr>)2 zp%(C%9L4U`V-MzGyH!b6QOQl3niBEK(fee0%9nx|Xbm$;(|ng#&x@U--Z#z)F3yUB z*|gf_yplEK=KQzY!MMd$Z*ha+pe^P#Is*y??TFalYmO~(^4j~oe_3p^BzsDgmuX2e ze$X67JPSWjB7-B7vSY6~_1SKo=SD+;FpB3r-$*~e7bdXV9RS}m-;_kmt;t9ol{mDT zl5ZhKSx8hBslNCnLQ8P#6Q>{37tI&HBCCdXSZ`VZ!(GO^~Xxm11)i z;MCynzgpgKB;40Tlb)Mf8)-MWN+>urX@5Gp;cd;xdecv9TN&Z`$d0$t5o+?IuPrXy zDz3>A%`xU;MZh4PiI@by|5OnST!`66m)>A8`1gqhg=ko004c=hUZyr1yJ#Okn8N;I zc}4uL0+UXO^D8qmk_do0fV6<)BV7C6o;U&R!(r(hoQv6L#*+%B`re><0?#4ceEzJW zpx2ZX=ROA?c5Ht!o9VQyiQvfG9y=H@FUdjkC7eBXy|liOs-nCEsivb1^yZW>Gdt)56adei1Z7{|k_o6EC3}8cmD_#DcK; zyE<`ROd$SP;%f9QO3lWxsM>qtw61B~wHD7k=`}eqiXe8R&duWBv6a;|7wZ6e>EeWR zg|7c)Od}C}I%Ta;d$sX^0`JqVSZFYJaN|2J(a5Bm%CT&E$=G&u;O03Xs1aZzh113f z`Zr=&;qv)_C{wHJ|6b31tADc~>MbxGIkR8b9qUXnwhhuLZI~MBuwl;qnW^L3<7wgh zGsjVtW|wFQ_A)S3@spdInH<8Urd34(c;vi2(Aj6GK2}vkU{Qk2Vsz%kO-VN%SW%l! z8qdZIW|t=drEFabDXL}0Sh_}xt*+yjCRXu2cn?g_zW(#>c2rL*_rqr&^CB#^wYOGO zCc?(Bu8M`W+Izw70SV|b3-eEPNkJjZuSsl z{m`ymZdf`oZGB^u5;NpFV;2R3s-w$-V+}=CT+$>oisG{V*Uf>(tY2gEtPYVryl?{6y}&xbXoYM2cg^1KtKY-~ zQN%=5p_o^VZaCtM53?7TKS$cJLrnQ~LP!Nh#*j4yCF&2uj_9{LPqtiZ|29-0iDA80 zZ*A3WK4O`_1@U8}ZLPhw%O|&uKBoVx1OD27C2;JJ*J~w8y1;o(?Hec&)m}X)WTQfNqbN#wBx7 z^y~8pZK(J^69K3vgb9qS&%esIJ(s8%`yx-Xwbt^`Ev4M|dTvtgk0<|&j_b>_?LmRv z%Cn~HRmlYu1UO-BVfdNL9rz?b;GXcvmdecTPE$9udmF#7h$Glz&y@%!057?*B2gYNfpe5cuEXweClP zZ1yiXURg?RM*ibqYtF3=@$LaGq}bpF>3g-LY`V2vB1HFQo~4IUfK>(iDtEj6+)NGn zZJ=)_vfg7q=Vat+&IsZ1==E|**P+L7%FoCh!Cn9TU3SBNlu{iZ6;%{#OWZ(Wn!W>J z4RCkvhvoeS9833l3#pp=!drNcz})xe8QS%O(FYvQ!{XM_hVf}4zLsx)F5g6})52lM zn7^0U(F1-6#k1@y`dOoN>DqW5AGfluHG%dYa4f#G(Qo-rLI7VkIw2Q>?c422v) zk$dUK%2~#B=WsY_j{TyGD=XdxV-Q|@uYbvdqrmUqV|ZX_FqzOI62RP&h(tx8fd{mC zfUR%80)I)F{)Ez#)1QY_-}cSw>Zp+rASL&$&u@n^c;fUy9#HTm-Sm^>Fx5~2lSx|s z{F-Cyr+##edMAHQMnO3MPf`b!BlI7p{^KJ&F>-pkJHGpC(%8r6R*;Muf1*d$!jCYz zN3meH=CZYO1GYB_f*?V2l5`nhxWX9{&l)H_*>dgZdb`1+m^i{nGdHJ!8Rn4;=#6DpSJ5Qlcm#}T-0CM8 zmkHVbRT#RAwXhU^2H{R7*tCFC5I81`9JXpkTg(fS+@(N=8)*BB;^VTMIy{NB{;E@T zEKDUXSCt#5lr~vSsO05iFk5&M3=t=cEmZFBh}sQ4nf4syb6~a=a_`!=%Dl?+`Oj=c z&;DB$@=28>YH6X6Cv1NDY|N^xl7uK~Iv?hmg;CAH8w0Ta9N_s{RI^CD5Sq8kXoC}vn|*ZFX+%20lomY z9$}*g>uJduQxG^YPB58n(Q1yLO(Um%bVSYTd%Nuia=`^miM&T01=3xW(bP=K=(cJF z(Jzz(oBxEdgv~e=``cT`I`O4pl{ha1mf{@UYhrp`L+#97TkoMX`~1XrPU`ikT4=Hj zIBD1)Ja4f};j+9s73!Y;qv4_Wk*D>Zj-|1FWnQOyh(U3nYxIOZ*(wu|{<01k5qsziX+6Xd~Q5~nUtu_*g$7v*~!qq*68Iy(yN@dN^EnhvK zK(I)yQp^KveNmF?7SFDT0}Q&MwlL$;n?Uz&0;XlilAF?xq!MNk-u9II5yMd_db-LI zEM;iM1mR-7+c0CEJd%wo$4k_Z(y8l?TkflD=q#+mj9Z)H7_wGm!v`6JViy$B0Iyo3^yHB65Zp zH7hgM=ONk&06EipO{v$E1e79mD3YJ}nusPr(Ge*ixS1{kfi!DGYMk%Vy3D0LEOF98 z?g-d&lx~V7DN`hE1lGRc@$rXZE^>85+`gT3kSqt!7qAVIpssHHu__y66p(*F-)<`ECY+RG6((g3|6%uS zvF~uu$WJP5ZsJn>q(My!M}{P54>k-Qt>u*z=$~ZoZF*4PFRay5OqPgg*(tDBVW9S; zp{!MrW`^%QKy1Op#b1pnFj_28Wlp-ai+VWxYiGK`M9N|8&jdBijr@R4?s-ZV&Ink}w< z;q9JW&h>oNL#0@`dfO+heX(ItJBC}PmiS-+plT6!P*d$&Fo^HqG5$uYp;h759|D%&%i2YPWBR8W<^wr&@|6FRZoWPdRfkKvX+U7pF zG{MqSzFzCbqD^lXZ&VWbC>#$+bn$yx{Dp;bd#-tZw3eYW376S+(=}&KU%(dpK25zU zI;7WS-iuRlwKLR=SWg6UXe=G6wh1%rpYZ$}G|ttNcWh`G2?*+kfLc$X=zvg>80UUX zlKE3!37R!6z?f(DKLI$+=|fT@ep%`ICeoRT1=GtoT6J{}_5 zCue10OLvb&gmO_q$EZ=HO-u1Bx!$XZ8yU2*8o6%mH}bEF^WdE|nNWKFt%oEMc)m{2*ITzia)0 zlTPKPUrgGtp$X7|lxv{RW}L*L(PJAtQr<_S{0gL(koX`HlcdmMf|X}ljW9j&&oao; z8#aq|WpiNT9BJLn<|7!+4cW1Un=dSRME?2w%(1{hmOQzgmOP&3-md%-zN=s}z~+t} zQnDzuf3eMEAhxNUxDeO3P`Ke8dXI9b?Nd$Qxq0a2$+zao!qsllj3>ws!NHN@l#n>o zB}Tb+qf#Q%=9zAkG{C`Se_z+(=J+QNIYuYGqcSsma};TI9_YwLGHI&uz)72*({1VC z0RCgaXb6?MwXp{YYZEFe*Imd%B@vW0opoDa+)naeRt{ozFY6QN%0JeBm<(-)kQh*WpJX%UaA3ahiHl=2qosK-m6IQqAJv8 zB43G{J)X(Ik-8Q9WMnRem14*tMq|DUen^^G&kn*@?S>8>} z8a(chu2A`j9g+gT*8mJeIZzOt%>VTaiM?Q{t?rDet%HnOea7t&L#w?f-pya8L=*Wq zu@)n7ZWi9XuM0VDL4~v#(ZCbrE{%em^v<%}6+3MRUn;w@jal7Y5w5~I(^}`%ljy<+ zwqsnbylSOw34)fg84ibQ-)&su(#oeOMA4HyV+W{Se5O4~G7T-{DNwjBp(6cKON%l( zb~YNVP~rgEq;!#&60kybh-0EtRnhd0cKb;KyQa3!b;G4Y7*2omA>{bNOL8W*1>xBO z(Nu=A8xM<&7Ph7kC}45Zg=hc|tQ*>fsXE#GR#wsb{+|#A2xkF+XyoUrKSI~trevw$ z6-QU2Qta;nSfrd(U;EW`s19eaL=RqP*aDPee#CU-R4KyNQO&OYGEnfsU;7G!K9N9u$@NP zwJ=3;es~GDxzZJJ1hY+cTc0u6zUOE5q$Z_Jexxs*(xoE9T;G5@b|BDfK~`@iOowH@ zBNI7M8~sv&9LHB2B^pFyEGXpIC=iuxpCl$$#HmMONP&+y>MeR8-)Sa}-Ta*;R0(2aFLa!U zP}Z>t8hfX z11rtDLBlAZD@Ub&`yp5&WBa%c!81PrH(xh1hXc=ccbhajvvk~!v5LA&EegS|>7tpIj&tLl1Xi(sa`z{Jy2YJfcV0U3A-{rHERz(z*|mte$4 zgjZEvWk%-xjN1mnTDswGp4w;uFss5EK2#rvl?osZAI}Fl_MvzA)b_aBEB^R6LHse> ztoeC>j+abNQh?Fx(EjzSKYL-fmaKi+)b9g$aPGU1_yn;lr>ZaMk=|Z0c$FK@FJ1}X z3`JhUrKos7cg_z9&djmBAhs3l;4X(SQ_oNC*yQ=hryfyHMw<8t9Ee|h<`CJ5FR3skOn zOu>a3)k#s;5e&E8zP$l#O|);Rn0IVjxDbj8Eay$U&Q(Zd>BY9JjbLS}7{$H`G&^Vc?7+jiQ~bSzhX( zjEIDKoHi)GHP0#+eSa=>@3s3* zX67DSGY%2}%ppHM+;I>X3z>P~*5i%8A%g#Xiegp?2Sh7-s?xMtAZ^x26~=Vg=l<@e zn%=yP(_TYHV=n74$R!P{5=C@>c1IoOhA|4&JWLNz?x%|(RvB6wUMDUqFzNo>^Z^=0 z6}Y~f*pTb`yx9216knfT^3Y$u8jE^V+(4<;q=)Z})egV1!g_P_XM6i+p0D!p%zJ18 zG_P9_{Z(vB#3|N+Kkiv)R~Hba6ksrKyK@ylkrnWnM{aXRC^d^cffaRez&z&JPRZqd z&nfwqlFpu-Dlqkz;;yHc~*4eHpz?;!-7&q9%N9>Uka<%a6E_XYdCiWJmk zp8#EtxB;{O+X|)Yh0I5yE};>~;d0S|oE_#5nrtQJ&hj<4U;*1F+0s>+%PC_Sk7m4W zfPtCkCqTCGh-o^!sEDCNxtZ+6P#*gPy*t3dM0--W_wIUwt;$FORtpi-GJ@EgLhfVs zsyaD+m!!MAX`TOKvWnys*P6!<^_@S$n<5LDqlZk%vdtmUnC1Uyo8-n@VYf$r0Q?0@ zFmTJEnfbtTu|5ikY47g;(Vh{(4rl3whRy{jJH?c-wd6K_#id8}8mR@DWdQ)(=WVTP zh!@*~#!;-90xI0Rk2hl{ASQ{D98)y!V{MzEtg$}^2DNfaOu>Q1XtUO82U~dGMeq7G zG@}7SOr8%nvJQ<^{=xt4S8;O0@!GLsvbGC*2dTR@V6m^bHbh%eyE?Eeszq%&?jZf3 zrspVhnmtgUJ^&&kDk>2s4?Zm-xJYoJ<1^F>r9r-M#@qO`w+hK05j6T4Kz>}tB0Lr)NfD+2IBipNaa@qL?^IH!T9;r>9C z8L%p<~2?onFCy7^NW|-?e%v{wi_g-0?B&?5yYXQx$^l5^7G><6ev}pjmlcR2Ov# zld|b?xdXB?fr>-!Vw&q}cg;FgIg~(PY1&L2zoZf$Fti)=hW^LM(hvCoB>+B^JWa;B zi~|~)KhK+l06e2t+OV&Hso&`$o=!AUNL`b7(&Gi#xQUMEn`_1mGWPo6kQKvmRv@aT z_l0KW9P-rTByn<%7KG)5su{8zD+>4R%16aaS8L{{IN?Ws%4>t~a>%Od5<8`07Fv(h zi^8l<%%9erfYpMqosrqVCt)-ITV#d;!akVOV+QJzWpqg~r`V8W_C!olhN4(^05w_^KiC(yZ}A?8E-fwtT9E4ROz7SfT`>c&06 z7#l7mYVHFPlU}A08&lSYdIN&DFyk9vO}pr=^d#eM4mBM%5cWM*rU5pKQ$UMP6vLKl z^Lzg$8!s;o@~gz=FNECsfSU=1h4|8A()fIVr=UsiQf#Zsz_YXGAsGvBO%5%{41mVs z#f4V%x(h_960zfIDfZfcc8#|9L-_a4R543ntn2ceNS_4MB)fhH7Fvsy((QW}xJCb7 zcfWCD`FK1;)p+TjjXK8l_hVpZvSXtcwkyxf>)*!e_Wb2idBNaZcRI{^dKLKSV?tsL;9Y zblO4~D>UJ39HVo!?b%Sr=0(+qB*;hY|J#bR!EN0$FLX+v6EMR~6Su;1H^&!)j8{!G zX;IMJY>12~8>~ZVmS6Ouy<0LOSbO}J^d+XAz0P+N`d<=l%{b|^sUMjMQh8mb)!*TB zB)bO6AkZN%B#mL66e!m15J+mbbn&xfi1@BoZ!|a}3Y`DPL<#`WgS|EuYX7Lh&+9y; z7WqOnc!-w*$xDY8?v23L^^`cGmKxdQHDYdGwXF7(`8(>Yp+P-@IE%K92C07!W<}Z- zIB>R~2G18bPh=dt5wAb_7+)zk(2iJ_6@CuSe=$v@*#QNi0m2;4qU(BvqC))dRDmev zk6&BDguwM#;VD!aa4#ij%<~-{BnceDP<76G_d+8%CtiU zODC={ese{rb~EQh8N#+98V}i$^Ge7#Tyw}Var-E^|nnQONk6D5@AZ5+HJjJA*ZZ)w9s4}c>&kI zt-7@_et|!9O1(v6`?`6u)rnZ=lgA*@ynC?$nlmGPBGYmqFP(wz+UB_)6~1jql# ztV<-WhBw^L^)H4svXTUvBw~0K(FhXasn9GI&Ss1*NG<8H45&?7Q@`omSV?UQdO)py zh`0MR+I$?zi{-SZm0Gc+^lg3I2@nriA#HNu`Grkct70a+xxj|aXWM>$0bwJVus(s{ zXn7IS)F&6LSB;0P6ArCS*@ha2xhW&>n`R>>2|TNltXwOvmWDYk0<;_d>-LU!2*@+- zS8}JJo=Pbs%Qyk1$46tCS zV^I2E<8p@0Zcb~hzrqr?gU72n5iPPb=uI)d@n^J}08<+08(|+F6>bNYB&CH*AJKD; zYk6Q$GgtrBv$F3mtQFDgotO^8_%Xy;xdFbL>}=_$9OH%1!6~Z}DG;nK1`{tdK?Bwa zc`PgK6zaGF4lUBj95aO+T*(BJF{_|$2aFO6kLSioVAOf~lNJ_vq%={K zn}7Izu*^*mek@glwVv6I$lvp3Pz=9S{xA$67_MyB;vHx#;m;U^tiHc#MCWbZ4{)^LG~94az5=x&WJs z3D~9Z@v^Rynr!fw57hs1DJBYkKo*aJT|pSbrsxJJDJ0Q+;VwA#OJQ254HM+>D0?BE zsH~K1XN$gDWUu8ujKV&1rfyV2YA4|8!!S)sdWAc2j3B(C6ns%rE>Ipymn(FomP_`p z)@ZslrJXHE00->Wbd>hi^y}?WpC5w|F+i~K0{rqeM{;V}{SVv@CqiVjrc|bK->bQD z@tr-o^y946eg5y?Gj8b`nyYBPWZU|#?8HVuyxR|eW-;9=FHzSN%t2uupOqOvqT0N$)3FWz=SX;8Q?($!b* z#49%;9(yewRu$X8{t!VGOfg;u^yuP+VsyUr5T$;=OKKPfj&)|CYpXuL>+p0g!RB0- zfft|Myj>>=yVd;jYv#NYr$b?K&Rl8h;pg6}dTRXH7C)!9TX0}9NZ)yjcj|rJVFm| za&Ldl*Df5``o==cgy!;Eb|#`iA;Zd{D4FiLw=-|QQiqvraS>Mu{yM+(#v%UqWEy| z!e%{abKHV-8cVqyjv;`N5*W=F_U{_o9bJnoE_oU$f}-kg=7y4X5S~IO5dAfF;lMOZ zex%HD?i%A=CrLbb`%2$={~AVH>;6Z2P_9cyndc%E$WWpHyj2k`5*o|nToflF+~Of1 zvC(5v2RU^eDcpqW$>aZa2g6pLGwI>n{}twVpMK@lfd%l?i5M(fe*_`=ox6L9i(r7P zr->5bHGT3az4l6v`=TQuHULma2!!ar1xd`Nm|m%Y|`>`x>Jyf?6#)JcR)Ljx2J15C(&u5#oy^akZ-E zf@f9T)aqPp18@Uz9u(?Cbknc3Y+k}ifOV5)vol&sg23+Iy${-ZLs==IcMO*c`lT^j zGiu?P1;8Y-fdOW{&7FGruXU5ox*EQuhm09u2~Jy6+W!Ua(+sj0HPI|*-I>H49E*O- z78Isj$f4>;Ql;W)H+f3kXieAeop~Yksf^LQ0(LrIL+}>C#=A*GseeHoUjjKerMp$O zP|J2RBO=DN{+h>zi4`rtrjY2(dr5Kt>tf0_(4hHPJGts>dmU*aKVBJ%{h{h_kW!z& z3_l-({EUp!RS{^!cpVs>AS|ec>QN_?qtEhwLmf$^#^>=SyEyVI9`486Z+hS084nF4 zk_I6-xw@+5-tC`5u51uKY8JYdibV$GTxa|p7og0&Zz9h%gg<)S7u;OGVs2|T(@1^j z)a>{QnYh6IU1v>9e-5Q!{w7|VOnZ)6a3fBqAO>xiGQQ@UHC^M?+)s*+m6Pi17Gfdr zW2za{N4)&NAmn129mD??odxAoaptlBdXuja*ll3wWy1 zTZfq2$2jolD!o$nyeZ|g5sHu|>n>t!vj4iaCpDrkoLq6~#jKp1ssm)|IS!#T2W`)u z26x6sVSHEHNHsd4Y@*Aj{1g_4gGP`dA)YX#i_)p&v-k2WgfGgdUwU zJa|TWeruFY#<86Bv(;qq19`5DFoRcKAo<|?Dp>xq-~`;y@-u)QE}2F6W)7$)!l1u9 zQ(jdsiQwzR8ouKFZuj{O6l0QwpQ1FogaL*Nu(_+R8$h_=2_5(UN$j3{hS9jszF|NAbxXA=*$wW+9_zeD@kqIT?5A2YZ?JK4aK2P=xw?N>kfO6h& zOx$RVSV;ymup6_S2&8Js6HT4{4NRqsC6w0X8t^FTnm1QhTg$DV_9+12SHF4b3~o5$ zuzwsTu$V^%7qBW2u*%_1AB9{ys&yAacWL;RO#eug=%UP&D`}^uGW^4r%_A$aw%8pn zhYyLz5S17|vP1D5&J{(PPX6x~*l6*0mNu7Rcbn@iIq7lD~-pKnC(TeC<{F?gkc*WW(t3_Q1KRlecO_GvFGF;t5XcHm$N zwSM05Fdynu;b`EWkUN*$D~}jDqUQJunCJF6mRI1Dvb9ozoJc=Lw9sZp*!IW5_XIa} zs!qVCzs~OwSfhnWrZx}-URe$V7{RO2lFGj#6N7?mI{qp%OG3=Z=6Ugn9~u8Zi$`1k ze{7v)SC(DWt^rAZ9a_$mQ$2dVvC88;((7Wiq@OF(p2Rdh0i`LY85fY>4TjfkEt0qW|72baQHBI(+=is8cjhTZL-!E6E`#p#@GXk$xe^AJWhxjs_^cmO=93a?kQb9Ow zDsfJDh>z<~1m0JH?RbsnhcyaenqpAtK42%{_gweD>$6=~@boxwohg2tktQRbCo2*G# zMdM25in5#JISWcRO9d#SP+@P#>sE* zj{YRj;T{*xQFTWZjX`h=?L6zJaTVG*oJ{8WD&8ABlR831ZN#DtAnrMDdh?J2h-WXq zOUJ3a&iTgr6D1pm?As}?m~jxt?R4THa3J43LXs(S`BiTp(fu7kz=illZtHwnYC^i7g{E%DWl1_$TxmjS8`Y9e4X}VAs3VzI zm{t%2Gxt_UF1|84Mr3~3k!r4joG|K{Qj=kT@J*YR@x%G>xSH5ET~aUMCIV6(?>igu zcq4hUoeHzLE9HM*ywDf>E6`CF_*JMPe>{$;YDs~tZ44!s} zVWiK1JZm->m3pZl)%uH`-`7CT>2jlUu=*op@L26sjRf}S%?7BH8NqbWEMA~I5Y!#< zYu|_X?|v=v7HEt{plal@A_Kq1zGeAtk9Ns=)_yn+g^rds#mRa)OaIAxxyo|+L8T>S z$({cTBkh^B-wJtz z;QVAYLP8+}&1{*PLft4mE??NCSc#Mtga+fWe$o3dsq>v+z+;j%ppw1wWU9Zg)WH5Q z?S;-KBTA%%juoEy{54IUd=U@t{UQ;*(q$yn`3tkScY6nL6E%^)n+ypsqQk6G8O=Il z%@B6|)OkkYCE@oBDp}VeBFgQUmDfVN_tV3Tfux{5K0LyqKKWEijH-5ZAO=3LCdMq@ z9tg6WD?U~YSo^{UEQOHCW z`0_DIsw8(C@s#Qle?}M4oQYVp4ZM-w9jHj`>czqH+m-)O+;qu@zQeH2obItm;`x3e z1L9=UzE-F81M0IqyXKG6)aEeKO7NHQ$Fz*q*FlC<_>X71_29h=ts zjyY4hZqj%@v%=)FeURTz60oBA>SzOdz#4I9TI;roT->#)Sp7-Xv+{8f^k^y8bheby zVYjP~vjmT6wc@IYZUVcE4vr!kqPoZ+V9EVLYmwD0IP@5!_C7_{2N22UF0;gH&+Kal z$NkD`%BThi&o)4&miWqIDGY}1^~=KxDA=w0bhYVmcPRFBat^31xF5U1lIGxg6fqlP zp*8FJ9>1zfo##f4TLT>PA|91bw4a|8ejM<1x1B*IVj&P^B6FF#IEMYLbBJI;!xK<(AyU%pI#hq}NIDrXvo%)vP z_GU-A>BDE<=MXVIL!K!GIb;9W-X!j;z5)3yOl9Hs^WKm5QR4U*)l-_Jb$y&%@x6qg z9E}?CUiN38$qMoae#JY;02Bk$VC&tfAAuXU#~K(8U7nixb@1mQc@qgeECHHd_6y|; zeemCZ@m`c%1xRCxRtY||vO9`sHv)Oa)1o2Nbxb^zKFRmzG;v@zvzqf~S5-Zr!p?3z zzK{Y3s*%R-D5V2m%k(kh89cY`V{n{^jfou|ZO>_+H=~7cqJ^Pes$xj08nx&X!iZth z+4I}{l;!?<%x*6rFp(|0d?JX%Ld&Tzl=oV*BtP4<=VfXB@h1*ItkzM!2z`E8{qe;Y z0};&ZO=#CSVTgJ4j-BqUHhCQH5-VG=&;H=wQIA}!546%9cvIfB|F{g}`1u*<1_igz zy&T3LAq&FY9fEF+pFx2KgF=NSoq=^MKQ}mkt~v^@wmCxf&Bo`3K$Bx5!WJ{Th?2Z! zesWVwMbV>sRZKj8Tw&P3_598~L7;K@?kao_!yF=wusIrJ_&0r-$ud|3z_X~(DUd7U zjVXgI8{v#Kk#TC?v7|XzBEHeBuVgyw2BoK=Z#@U`n47Q+YPqsQGh`ARIXAjP)Yu*D zZUVQU1vK_uf69YL^_lLc`3Bo038nuu?({Y@BKz~f7@POsKb$`saL)5&K7I}U{6Xrz z2ofbXw%oA(H?+fnY!p9}%uVD?`vuhep=P8G*|ZB)vTYQ{+ZsQy(Z537WpIns%)K;7jr^m(LLtZmyUCv4EdzPbO&X^@sAb z@N%WW^fe)9%3dFB=aU|<`c7h3AefZket2_Oqa9DSRN}nG%D49t9Tt)?*knIg+9k~J zPVbBooFQ~~{+RE5RbBiNwVp~SGz{5q=4Ls|s%17P5IeuCTMWN|n&ej3Ok_ri2+bQj z)~8ehE;UDNlpfoKul(aAYe}f(is)P~?OHR@C74(q#>`YPH~rGqI=&F5QcjX^4D8hq z9>rsMR@4~NLX)fbp=R-W-j^^y2Dsy=@e1uv-dRr?w5FD%IQ7P(3pGxUqe4(Tg||TF zN<#^BbboJIUF4?IpT+lm^5>%yE0j#VIc?{l+WY;cJVCu%zTBt7PhrQRom%YaC}UBV z?1g-#IKp}Bmq$kKP*M1R8V>)qFMm%vSfQh-m)gowT%f~4xdckr6BtwnqnZ(bxe-iq zk;5aZJ|EPxdEfv0BqBiiY`mcyRK9Z*4~%%awbghFtRt&@vaVfmzIvhVJort3Y*=9$ z&(O2=3LG*U?S{^7TQA*mSOr$5l}X}>Yk(4MS~2QqHtXeCY5^MuiL$-ZsnY~r&D(Se zY~`v!rPF)Nk$X_Vy_1(1WYK${!b>j}IS4W4`y)B$xk`34Q@WHU){Iky$??bY=KeKD9d}*ga9& z5{%rI?8-wL!1G3zp(w_eo;Qu==E*wD-W%oexw$yzb#Qi=5fb7z$@Xw1M^C?!jew>6 z)vjXu2-E~^cmJyi8iJajB?`nDvky?P?4k$esbDBM-;#Sj{(E)fxM^?G+(6S2Z+~@l z_-w3Y{*U7_-#(ay7xTJ|(F*WITtJ5YzB}A|J@<9?Ziwzl0?oCZR*!JC=t*hv>5sej zn^Oz?qQ|9gd*QpNQCP7&wrg4cA+Au}y-_Es&?t|QsKoYGES@pBehZ^46?qck{rqBu zR9fM6cibSl7zKFC)F_TTHyi5X@@98D6Q~65meQ8!&lZf4pXvaV5Q5x#AR?5|Ygj8` zY(PWhFaKOWrpdvJH{X!U^-V`6RLGSY1?ED1=7{;XwZ9UAf6@u!?^AogE73I*B>v3W z1!r3%_#I)`-O|q?xqnPFS2>gS>)lmu%a+De?!6ft?X-G6f>eiW!)=aTRas=l?h?}o z-!8)5ZvbUnFExOy6IOFuGW}e46J?6{?QVR4ceJ^?y%599*|*@KL86WB5Az8WSVJ_= zn0QC+*?&zTSzuaYUtm!%jU8CXhtalYwrMYUV8g8Ck9^McZNTe(4&-*t)?}Y>*$0W2 zqzy`H=cKOcs4TgJld?heZWM)mLl1eWU7R>}##|dN!3L4@;Z0^V7el5eho$!dm;FGB zPIP~$o-TCq+N(s2pX3_M#3qgOVijEI_CF$zy?B|1Ki~f>-p!%NvW?56Cn|05K?5vL zitc`U{z6#f8w%vtegSE)8ANQg()1Z>T+oe$jMyJ}c?5O8BBr)5a#y!tVuMXYltWFV zh$Rt>G-NqXbV3sR#??d__}5Iojqhz*hkyM|V0NH1qd)yjeNO)HKGD(gRq9ShMq|u< zZn8hMAh8xN4Dw&3%tCNb>zqJ<5`(b+oR@5EbEqVk(*0@0*6W?(z&jy0Ge9d~be5&V z@H$jwaA*G>GDULx{%Li}3?S#Gu`EzaJD_CEA*go!7$#8Yq*rd&&a1))`(A1XUZ?E6 zD+3260jb)RVH@T!*6QR~U};sBY}Z>AjugAPU~KCwYqjn7Ly=8Ry*z2aWLtDQA2wb= z_`POeNM>4?ZgH;B+hN}2oHS}wOfXGBFlPI{B2GLg_KaF^CWnsmB40?Kp~5uBUFU>g z5_9GqJB=xqc|lc9pUDlrQac_QwG^1&b1^KN^2~t^9(HF5eab$9R=58Vhj0==a&-U8 z!iq}!4Ym3=v6{=*aWIIsGd{l12*IS7caNrsq$~eFkd#E|**J?#MtZ^Gj+;;NUlT3L zMX-#Ocg}~{=D@${s>ukzA$EWoPwU-4Pp5^B7}mD&NsBe9CH7fA=O9vGsp3T#A%`o) zVJ=h0l#MOnfQRpV4HmdAsTdcS!)aSeO|*F6;mY{}JY2(XHVC*kxls-90N=-;{8R8f z^4l*e|AJ3J!TiwNCvV~HHuNP(Tfv1P5vB(M`w5AD(hFgact z=7`b%_3@kF^|f1@pCkFp(_!UXzNW_b@l3n2i^GI{>y?T}(zB>kC7W5R5zjlQ74~yu zxk^$t)KXWjBj|c9>+URYerO?Q3k6|;u15Fl7zT@EdIBWbyb)pv9%(i#fxnViM-Ufi zd0k^nEympeSDs31q_OyE#oR9_0}16&fskB;XARW7P{km7{b^#?dJ{pw6->|JtsKV} zI@(_~^Xl@|a?1E81@$u{<8*{Hq)i?1x4sUEjEEth3?~x|OTn(Cs??H$P*me&zP=57 zmY45R=+8kMfZxtEc)CE~wQDQ{n z>lSD5Rl@2?(LlJ)HS-Y7K;+Og5CEZbzzx%Pkd|JFJ=C_UiW;?y^;(fA^j|>D^NA3(JFw?itPT;i74kY$1Fb7P=>Jjk zj2}?EuHBM=4GNanmA)hUQRfxR`kLHiN@1rsMITMv9!%jhMO+TPu*X~Mod;TrcT+>p z+Egfpu^1#>_0R?tcl}nLcdnKWiT_?Dm^@HjXxkiU;0{0c6= zf-h5|rK!Qi*9BA4f*NhMf$k3laZ|L^g4G(gC2K%T ze|V^@%9v&n_GUUfqjNzjpgjfpL;!Wj_kC;GJ9?r2T1?7JyR^?zW_c$l3dtX4&n+4P z%3G9r9-1h*LJhUE4^XCE6fIDm?(K)y+q)yA|y6wfI&V%`j_YP zKW+-__EnF(C#JT6Od1|s>$U5fZ(+!1q>V`-9NWfaOh`BHVZV}T;Rc@_kzd~n=g*(1 zQnC%L1S?d7|7okjP&(EV`^>(<`Dn2S`)5wRz*j^S_Gjr#%M}`&rS$zs{j{qePqcs3 z*14~b2^Ju%fE-;F_{P2axf0Z9wfk9dwd?R7*9e_Sjb=Pw)A57ng_BUe@dB=n$r%?lZ~g5jg#c0w4Vc$6pC~g* zgAi0_kE|;nEmc>=Uk{;3NfLl+uB3M@+5f5@1ole;^x+=-xLUvbeILANj0`ov1R=l` zu?9cOP{vz((8l1X0(COGw%q5h97GKto@^e1g6q*4eLPj@NJFc8K))&xLjnO^3YQh{ zbn3zP<5!OnRI(Ba{mtz~cdR@^!F(|hWz=Z$0tj@N@&x0y<;z1B>xYD*6}S{KL?$!^ zvOB1YG6Z_>1RbwrUwqn2?eLg}_-%%*yTT5`PF1ak+Ts5w;$S$R-S&42aes6nZ5UA$ zWlEG@Tyi%3I_d%B)L4fxZc$> zqUvM~)lm=FKNznns7UJCXd`S>O-eR&wB$M_S-V^hAh#dmd%^Eb6A7<$Pak>g&BuJG7Z-F+s7J zsMwhhmN#g)(ksOmS8pcB$sw@-^*`TrPk?fn{hLU z%Nu=pK=y3WEER0wP%OS_i+VAErMWJR4k7ob_8FbCf=$=~GIR)%zj#Z~VC08-76|E@ zvm(FVvUsa`CFk}eE7CW5#Mc@kq%io(eo8y$3%?Ev{|szpXE3?{ISsTnx5v_9I;3|O zHPU|wN}g0+d=QCE@YFHf>IdlNu8g_#Gp@2Ap_1(CN~Qa7=toOO(CDL2uA9w*IFELM zqXU?Y(yo?v%~%j4$OM35_JQrTQg?GIIAT|2{_FCET>6NIH;8G6^K#s}2dqK76vx{e zkk3W8x!xD%6Hb*{3IMrb%9lK7+`6b6NTrqfNa8V_WvlUL!K_+?^*4C%)`;sa^6H#ZdiD{ZIzL=_Z@Ar5vRWo2VPufBO>0$F)#Y-MYWnzEU&M6r;zE&U6#m1y} zg_7H&I3FC9a30iw;;W00ebM-rtvAruo$jwHj*$2Qej@J%P~o*b)Y>7BgO$=je>-E2 zWAM8isw+oh?y$69swxTSShZ6yb3xh~W~pxN_bK(2W|E@M9ak9HO6(;Dx?BRcm%k&S z_z(bZkpV*IUqAoKA|(?fNtJ#D&8#d9R5G|4GAN-~5)p7odr+YFM zD@{*f>umr1udI!UZ}q0+NJLB^wCAbW)|oG=5+ocii-G1!wKgf*qHrY))*uI4XR8b| z9HrhU8cDY}Ggpu-Z`;66K^%)jX_DoiUIhk50z6&Ct2p-Rl24w_OY790zOJnS5q1ts zfp5kxP^*v`2-56LotW=mW2LZ^egHmVy_RD=lTY|}zKogal{dm4Dr!9+s2x1Zbs@o) zFFc-t2ztbxC*{zZo=-4P_ke;G1nH6O$nP-e8Q-v`lnMBbNcg)BTI*+#%Ok-j^EP@U z@Nyd8NIEkYx8;eI#36eBNmsG^Eh#O1KeX92+i>I<*z%`UHOwR1;; zMU!!6w%65!e`{OuLXDjgS4&g?d+R4u8za1={?aBtFB?m0(NrhU~zLtF=E zO*#Bs=mTA-w=Kj(ql(7Ua}1a1Y@@}=eEss(JmxDAh9OF|2{p@X509>lU<390Xq4&Q zUt#lg{^WebAn?KMr!aEkCBfZ)lR55Zj@|4_E~eeUh=Nb^IueUFy-F;4kM3$i1!)C} zAQy0B)KtiwU(soA#7t9%zGG-?QO8e|g?$hHru1)PC=ej92=96MZ|lg<0&|is74#!r zMa_Yr5M?rYg;eP-$PynBYsFT@0eoRs5{VRtGinOHRPeuU@l$?t=nazfdJUDaWJhY% z?%FToqVMwgw95Jls{bnkDs&K}uUv3mX|JjWz!cHx4LXwAzwRC0-wQ4O_;Sh0#^XzE zazF=e3gSK$=%=2DiB<#cwdXm1QxZx88&IlX?ra?}$g|mmd&np8a(bhLuD=3$VKrVK zBShXqzWOS0Rz!F5b70sqazo(X-sI$fqRN*+1eEQt&Hw!IRblnw5Fep7DSmaq+yTVN z=z5BZP{kwqhf78FxkfH7FSwL# z=c>cxljhg+{*lXU9Uv5TXJLu<>wKa=5`A)IOt6|yi$5#o^6z;CRp90zjX&U)*K>Dh z>oyKNS}SyLtCkGX>x6)dwcmgIoQ2rhPLJXzNE$L-I*r<%`PM*5zBk%_0@%WG7`lA- zlJgf#l4QerZNOHX4ldOLR{=gIC9xNmagI;Zh71qAW?@rC@> zw-T7xoxjg?>-*TTWKQELJb#iYrgDM%X;tsz^fR@?);()H1y1I2wP#u0`7O>g@0!9C zyPjOT?9Q1Z_K#a%PGYT02_fbIZf^GkJY?^CwE>?#^ft9E!9Pm+a?4~SJl{*3t%?8M zD7>83PY2!Sx#82$!hhLQb_lzNzR$_1p`-Josgu=uv-&LC5WHGdL}HBonN zO@Pw<-8+0iY+>W)XPpV6_~&27yC;3XC?1+eD{C}rDV6`J2MytoFrFkxNaO)}$?zzE zS||UsEIx*12tH8)A~5a4*~_229V^3pu2%j2WqTp?$`v7dB|764H)S?Z6-d8iz^U;i z>=66|`k2*$I@q60^BEa=8)f~&)&%Uo*tXtDEpl!iHX;RYBPpnN3GwS3jPl{dXDVsHe_rC_hLhHS&|ww2 zxZ*L2jG|E&%t+NqKBB_YV7&&hdH8t_{kC$m099h;htnZ2W<`IdgB+KNte+Sg)m{8F zl-wejBG~=`4(e~>3C>m(iy#sq_b2e!+Wa>5{KfGJA?KEA-)u(3pB`{|9lde9rnpT(c|xQJlrNRC`>UVY0_b z=vQ;d{sLF@ci@U{H%?3Ythp1tJCKhTW<#U0i`U8VQ@X_-Bjf>44Si3t;7wNQ`}4rS>?>4p3Dbb_Fuy4b zK-2w5?hY3QWMTO0?Xb{pr3m?@<}}oAnjRPLVlo^}w{96%eKy6*>jl5Y7wmhfzoTH{ zIsXs@n=l8<%o{=ygT4qnoTz_JbyQ06=&pn{lrHdBUq@f}5e$XWxk(j01EC;wy+kD5 ztVEHsE0(Xb0J;hg_lt0* zfz7w*ztB^V{x{fdqxu4h#g-kL#g=VVdJ;n=&m~K{ywuKHRvDb+Y?LxeI=;Q-n_Qo% zj7T{9)~>ww)9KGFq`@ia5>>-3T<@k!R^i>bD^kQ#uodY=3F$F(<)bf-x3sR&%QG3Vs;CW?LBkxeqBWlcA~afN+YN#nh_n@VfixTawXlnF8GRYjQBI3GzA zCxEeX&!F%tMSML75y`GLg&;B_cY+LjLY$bQngG~}($mqR?=DpA$=Z*PIqgY}{=u`V zW;Q(Dg;aVr8iexsuE#7m2Wq)vaK;jVHSd3*%;9L^{Ek{ax{Q?qU-a;O=rbxv!mV`> z;;o*i>#_^}jfK9_S9;bqhh2w8bU~$V>#QT&k8D;E3NN-=U#hLOLCf!(4`UD?{lule zwAg|vT6_-@Tm+RnD!8TJeY23*UJ8RZ5i&gB=vOl>8{F2k{uoKi5D$na@y)f8&YYSa zHf1z!@zPvLSW=s$-uC>fom)ywlEftyo15H(_y$b%-!T#2e(>RWfG_F}+dwC6eB!jtYNHH&ziQU4IFsz}3s97T_r$Ro zjs(*JR~voKfz%f`EkBj;iy&r*~$?;V*?Rq{f_Rq=sU#V;>v_k`;pa8O>Ly7VYW zNTxQDO6x7Q@)r{|7z44Dm@V56GFX9pcYYf2U&`A2HV}akNNj-Z+d`Z0LsN>Y(Y&(1 zR%q6_-M$rP*M<*@A#mRb1NWVuZt+dO$soMh>`Y6@UxKzG%g}@i$l2<2sM0`%q|>io zz07f;;kpmo)bl6H7i%j_Tm2Nk*8>S{^+d93hclM4gf&+-{x?Rt8uyR9G_Q)hG(7s* zh8rrmB&0W{^gp*iik7Q6$Bk!v=Aor0{o$O}sXyRn66-fe7-c|@{IP#VHaIxA;sA)R z;)hF!$h~QXUFAC7F`89TwctV(XCx9Uv@=Gyk+o|H3S&~T+$@+xi)f3+_D%Jkc3?36i}>4@1=%-nbOU=3bl}(i zj%vx4NXtpgwucS880gmF#^x)DIzElD1dmC(xtXqw_sED$p0vzduY4c8GtdbDbGyNF z9}Pvq>{Gm=V=X;8pN}i3!P zwjQP9_VD^LH$@6heZBxgo>^v6{tbZ>CkDa{&n1pRr@X~|OH3ZoH>(iUzy;%y2w4>) zRU0$Rzl={`(I#cUiYoliFC5I*s!_rhh=QlY;`_W< zk{y}8vg&mtg`fFiKV&-I;Yva9jQaFG4Wo%BBCHePjG#y-t_))Yt`6s+yP;Kr!#Dj! z>S=|c<8O!2mh`*mhaaKU3a5v%AFv8BHJ2_7^jDEhZ;=2SsK(<&9!<5(e$o?CEidE}161(M(;@N&5eu>?s` zOrDn5gos&54gh&a$0b~)N{v+!UPe=q3mMCY#p0C^C$2UlDF3oR`W>7@@~Kah(#?}F zuI3%pdL`MkXG+|)1p=OGaxkdGVqA6$3>tiw;&aBh`qK7bf%e~*_C(+(3@MuX(-Do2 z=o{4=W2D3K+%3rZ)L4wq>~HuAl-QBR-MG2K;-yO#e#f?N>4nW4%z{a@0kg;J?PTtj z238T13wd9OEz|8y4@j9d6ER4bs=gc*>10>r=r z*)NLv#YK30a>-sB()=zs4szud3K8PJSF?H$&Cbv#yZ%COxdmyumDtSKG&SHCH)n0r z-nkw)DR&8B_SW=KSImq?5JYkQLuM2Y`|#~uaV%HYh;1{)-ETaHV5I~^(TJzD4qP12 zqWyE7FRqK;DUUTFrQ|1g-O7T~<2XvdW~tTA^~$}2JQ)($+_}5(@tQyx_^X)XzP_TK zv*?64FjdH2LtpMb%6*(NL%1(_o?U!AMF=4LhvJ$1_Kl zY-hoz9AzH2fQxsis`si?SQc`R&Bv`4q^clAMHIRfMdEF!0#2vA;@OAQqGqTo{TP(O zedtvN#;dgNG_swA&cxv*b;p)IFBMkgNgm{-g!1|`V47X;verij`6Ss)f~sSWKS9(3 zTI-OQ=HZ~EEs4!1{%r{`Wv=nNcS*C(4p)it-F^MHt~DF40cK*|#N!6{mgs&=(;%^3 zt8p97PxbKD{nKatUpOqIV>+AYp**aJfzD4g+~32rBG9eFzJyy^5?eDUvl&CUZO?a6 zL%)XV+LV{azuQ1Zu;@U zr`Ibp0D~Z5p?y8#jKZM(s<_ZxyqqN`rW$AoYl6#9bP96(fEv%PrBEm{IAm^(_T2-R zI3#wt5QC!SpFM~`7F)%mMBQl((DGugQhOYro(iW2gZDgN7F`KTMCUoOKzP`Y+hYSR zkQ;Tw>U#Y)LF!}LF5|u{*RkQVaWQ&;$<1 zcwB=}B%3n5&^uwCRfY?4r$4(~r~m*T=WE+xmd#d^WgoYYkH=@O347TjXg%yo%1r%+)@y5hJJiHU&%8LMcjRHgS0b-ga7!Ef68+bm`i|nGhcu zm3>2uV&SCGdRsQyQ#;psnPiKHr6^pjI0LD3ve?i}?Um^Ssp4rGJI5K)GB}_{;&m&QxYiH$~M|6wdk=3J~I})`?>whJQXJMWY4T1r|QInyWs1=ls^UeECbZFr>ui@@;XXFGPJ7l&Gh|){ny6-9FUud-xKfD} zEx?Oqqw1IFi7Dx4nh2F|5DTN?qr^)*BzMm#yksK7N9A&kUstX!=3G7A!+*o&D<$a!7xvtFT;O9G?{owqa&9OD(!U zNwz@uvGb1=B(SS}VLGq9KV3BL&?~#>3PGV^ALn`%zyb=&zk-_B{HmAaji6H&P?3?Z zr-BT2R~_5T|Fy^+wK}RQOR%O3U(}~V~{`nv&caQo^eK^ zTGXg0;5Xxza6A{0HpLV6ALl!RCn2WDW=5|-qZJ-9Qe5+$cALQcYpBf!NzQam-m*GQ zXARvj1Mw(yz8%75Lszf*ctw1ge5N zG|dDFE&Msf;s22x>SvcRy|A{9-^jSp=P|(q?YdbH2~J`1H;VB-(qsHSC`#0kRfOt4PhgE7E#G9%`gh| zGe(1L59#Km>&rS^deOhT51i}fBNj?^7MgcNd2_jrFs72yTW*boQyk`!77^%Nq&!jP zW03<;&LF~quGfF6+Cl^gn+h`!y8lJwo;Iju(ZOxT8jvshQ)P?8hlB{=e? zQ@Io1NT4n58(oou^MnJ__ZqWQu-q2}mb=(Lt{yiv-gap4zXWl_{z$&dA*8R;$Q(u#x{eN-s6 zw9K;(>;=8;hF}2FtgTF39)sAM7?#9Ii4rM{UF@Q~HRR@WP9S-EP>&8rHH6`cLHa87 zujMat(3yL^_8n&6U&W|gV=4liwFYqDI922(P}Ijqpu`zRCT=V=I8(Wu=r}RB1z?(T zYeVelGc2r@2YBA1vZA!We>8~%pO)Brj8wv*iCsymASkqHr-Nh&P7Mphkl9bwmYENS zM~ca4gaLUyk@d_J{JcT$IBIn#H$(XhGW#D0{JR#8x?{-rUu8$hiLBLmQ|6-hB`nDX zRs98o;4HUhx0rIyGSewv0JTTu~>*X);{GH;H}cM@#|rVZc8!*O{TyQm3RnM0}BpwUIrZPU-3|;N}q)K^&sdytNtxujTEr|vC4L(K*yYU70 zkbt8bnRlqot#9py#zKb;7Ru9kSr7FUz+fR4w)8DE%VktZ(i>E#vK*SPFxSlrP*K!x zkt<`l-&P{4901{sX!I)0tu&d)$|wd&Tg(k2Ba)MBkOeb>U_pMMW@~7uPq{fiv#k|@gts-Ul%6!7)d0b;k%P$@*Ov)_o*hV77FTT&_eR^DJlk${xbUO;66?hsX zi>#c`#yiJltLPAhtlCzL-(~Oa&w5J6e0ZdSu(t?4`L@YvH7@tG{|c!-sx(5ivOXJ- z=Ceu<9aTMFyTASPRLU_Mx;pFet=oO0adaeSbQ zts@9NTEqOauvjtWqBLV+Vebp^73&70J-rbnI$z~QWYb8!5k$d7J~-S2&iknvxn)_C zK zC%y3)Y`Ny3u9=i%Ju)S4x^bOuu%P*|-y+q&(I&O-;p^PlBNaX?hl}j7eFtIOSnZ%#+2Co>;ClP86huGxsVl_^YLku|sTqo?MfV*-iZ{Dusj}>t#rqdJWt>+1AY^eo*Sf64> zoh`u!NYQV_Gz=Sy{n1dtv2&5$kj*J&bW3azJ#bH8H%8pe#X_Bvwz9fsG3%6&e|2cm z>EYRe`F>#zojh&JM?vVvo~Z$9uK7cI)p|PVAD`F;NcI#7%nSub(Q_KWn&RW3f5_R% z+t9a8%#sb0@a9wzDmBZN5{emYFyeTpukfW#offM?wKYcuK_oZ$ti5>J)ZcB@)0DP~v@gy)c&J>j4*u znS=uAw_(>cBmw8KZ-`w%&$qnP*t-ne)Mu&aSh7O{@~BriHAZZWTfZe=-yfazg;XUN z9;TVj+T^EB-PZ2)5q+eIE5l`94?C|4rHq$s|I+}Rh1SLDT?J&0yzWv+!=M*NV{`Pq zB(q1A?zDt#$A6w!L2hw>V@S)Ju0y>Z*XoGX2TA+Ty=QJ=PR~bJdS5S--x_(MKI2{rL$&U z+gGBEd#wV64-?iB2$f@uHirWJoV*pD*+LNs5luM4!0JlHz)}-nI^3s;9b1h=oaZJR zM(Y9QxEmFS85Y*DE2g(e(J;~B(NC^7(?o_8%^n~J_uHX#Mt%q|Uxq{Mj%nY{N7y&p zm#0zWVs{h`HMwJsi~RWT{C3>}I{NMNyY-O#>3Q)q_8oxtQ#1zF?|z?qm0#X#)V37< zHZd58N44>kL1#BZ*#8=TEw&hUew=%s)9(*?l3Zgq9$0@`tAh$U%J<9jy}Xw=`MICu z6o7z|?#IGT=FVa)3bH|;s!J&!Wl1~RT|Njlt_m4$G*}0w&LnU$a1YOiX3u8F9Awl+ zds|`{L^^{Jck6J5e{Jas@^W&_9(8n_U+KJp&>m@}F4!lfn`f7rVl}&4)Y< zR1kq5PK?#JEJTRcVgEp^O%vyrO_dylvMX9CZX=ye3$8-YC$%$N#~&*Cyup&QK-*)e z>)cHW{_CYTj8}}OmlCN*t>Kl{o~_1pck1@e!&?8u4pLAH2JC_XGZ|85o6^v4L10Bi zfn6VZwexuQK@QiOT#WLDsI>_aV<;lDDcXX_0#TpSUohJjaaloN^S7tnlqeB9ws zHAdI%va`+6FODqvmh{|w<4S{|Mx*>jC)Y@tzu-S=#bgq~v3+0QzhF&ZR4+F^r zkEt}o*y>x_8nb9Wg?YQ%HHXq@!(9{J&WXd?Tnvm=GU`LBn?5MI$mPthZ| z(n9dA`dcKH1{@?u=bZt%EZ|VG5JONa+^d|7h^F5jc;~!yevsZM6>sB4t$4@4H2YP& zeYXF`>k8B0q52JE>u{D68KAO_tu_8}i(eRuX6Mh6mE|X-7`1jX9r2VZ9TGMkn%m)M z9qJyHM3fLFwYrBDH!ylUyp>gF)4X1E$(+;eOsNTm1fFI!LKKrX#n>`)I~^L{l`JkI zs_1u32#h5s?tZq%*PX};9bx=Pz&*?unw$`FW!94FVY;gXn5f@q6U8K^dqJ|2N~|Q7 zBV1!J#_623=$ELc7SYNBk#cVvt0(wpO<~Cigr3#6)uV>3^(i-y2XwHmVF1~+*%e=b z6^IlXK!CBYd?v4+-Ok5)RngyOIop+5>DKQ9nSAw;g3-7rpdCDs)J|)I_{KM%Nkl_` zL`>R`XH&+L%(bW{uZzjyGgFlf((CzFWJ$?YP5S=fJ+jyTH}(|6%UD^3a{ii#osC+C zr~6Gpg=2)qRk9*u)5q75ClFU?4Mvj!kv94HW!F9CQr;rFY0Q^w(cr~(QApUMMy(1j zwZi^$xT!IMI=T#&^G*86-nKW=(|`V z`rvsaZUo!u^TYUylhqoFS-TNU&QZorjt#QQZ3YlnO8bw zRJfr@xH>{ZQ&y0Pb7oi1TjThQS0h@iCaOBPz-$exd>wGLp!U-vj!J7-TT?B^0Z&e< zd}gR+Wa5h<5f-FK3Sm?G_#-l7ZXqBp;@_V`5qqu~6MM4tuW~*T1=CJsdZTIcz1R45 z?-LdmP@epj;vv%~@U9v_=Vv<_O?-yj(<`Wds)Z1w&j&KHq3>Mm zk&`CWO{E)xN@=~$Clfcyvu8UK%0-cBe}xco)MhM%$+GoTX!U$dxSlVx-2BY}dHuv7 z(II^1Lk{SXu3f^6Rzk<+a3bY;Zlw}#>q@&@{b^d< z#A`CHJSg@i4jF8>Z8hLRtFCl>Gubx2DMg4`cVGdiE2*Yvv;gq?5G3rocy8x#_;!KC z4q`O5>osHcE9DM)fbH)`)yY9E9KV<^SA2o)uY8O9JUEt*ZOuOG7&W32jU(|Gb>23!zAtFil~UGD9r~ zha@0ikXp*k@9Yr`>cIrUWjm&W_?jx$Ic;?27ht<~4_;3bfYg~^`2#I>|H>O!MkhN? zA$AX2Hf0)gltEb%8s^1~alRMUR610QL%hIlQc+!-j z!n{2Bw1(}cRY9Mz=uvo%lL_Av_v_^P`Z7^<;2LW8ZidZnv3A<0=6&P|dRmz&YbvBj zuHI!OP*Tncy2^x{__ce$R=L-1A`YR4fP{Ja%`MfjEkiUVN{IFN?QuzKL-f(G;s{+W zigYk#RwYvoB)y#bx~~%8{dp;mby>NVK8UzH00n_?P!LFAQVdJK?wcZr<=np=a;wVl zvqXTBo~}Ek!t(O}*W-*wQ@(YdjKuZ789sh;MWRTDT-Jm5_vTAOx#i~;Iny!E?y$%y zGKg$W_pv)(7ZI(gE&jBaVOK$wb@V88F`gP|T`F1mm=={!6q;v7fNOOR{3c6Rv9NhU zRKmM5TM|VTUWNy)!MT>f^X^#OVJQmTNlHdU-2@*xT$O?B@eE;}dDs1`GgupEo|imx zU$&XqUWFKZZwf^io+7QD%oS4+{a~svduO~Z>R7NiJi6bdS@evl&?AczgIU~6{@wxo z1S+~4^#>dGSAY7jjnzoQV27~mK4?yqOuQinX-dGITB!Uf_wNI$1*6Q%yW@M;spK62 z)wz}CN?$})kop~xe1H+4dd^+^!s8d6VA(uGXvAyY$q` zW)MIic+b>^h(C4si7x@o6ydrE_Kd8u0>5TqYVAQ#-Q~~ZbMIx~Qo4lP{J13LEr{@5 z*)01BOY~^p}Q@+@47bU0eFB@_RE7DUv33 zTD>pRC9Y>#mM%!%!lipJTRz>TnbFfFQBaQh^A7upC;Yo7Yn!QPbc|8k=CHW&&^YYY zqRbl*8`?}c(Fni_asSYJb6fZxIz(&rYV9yU2_!k)9mv-DvG@xH&wzc{wfIMlGZ+eN6hJ~~%_@)hqdu2e zl>}5A>y8aR)={pEtQG(;P1;p|2BrNyEQZsftPZ*AIDOKpH$t0MXucPc{@W)ljMY-Hf|t&41;pdlgzx3aF|gx zgZJXC&D#!Y7L@i#j22*~-$~F<6IxGUBPPZe^Yvgk z^j5n6dEYf^xojbAyv6<^HvY8yq=WESJ9EB)%d{q9$o3knGas4L%3%gkNzd&Y_Q5cw z%Flav;dD~GOx#ZN$nrYWUpU5s{3`Ym{vty6WRS3G`nSFp{O|x~SzveuGtp40SE6@( zqi+Bk7SzNrJ;-5;?0Y3t_2Zvb03{_)=yhIrMO>?lop2xHs!`uN+7O6s9|fSr^6@;< zAf;U3YsAJ1l67C(KAxd|%Pq(oa?V1Fa?b-y=A8h}biW3v5zA11s|k%wp!`Ibq^U5{ zi`4M+442-Oqo3QDz#@M>ub`Q#sQ~+=r6wUIsBmMdUZdwf{dXk;5fYtKk80x)Q~1uN z2LOtYQsu<(=U;F=moW+Miw@@uk1v<$DKw+SA+O+8G-v0n%dHXHdYg82yM~0;zS3Nx zGtqx!^2BDM7alU6Xm7-BE!K>-(?4pl3p=+YNuh{GWl(5{aelJrE;@MOC@cs|u2Zug z3E94-43;z$QgsCCOlglVVNSp-0bL7AO48ByA_v4~?(s%`;gXh6G`>M;JIh zuLU4&Wj>#nF)3yHww@oeZo5|Dh2vA>Qaq zA4k18Su;(Te2JwT=wzsC-B~y6KnJC0LN%9vTr%_n!<~+vQjlH9UH*u?{@bA{S%62T z`C&WjJ7`+E)E%wOfTdh9HzZ=}XpP&C-1yu)BZ9biQU9<;N+b-jw}!x+?~w1;!D0f{ z??Hc)_8DW|Cto=?XMD83H}jCw5FW_Omr!IiG8^ZzCyVKm2P>p%&fX%wQ6_v%O86@3 z;q*XC6t(Wnm2k_1DGP`Rj$umi+@5y5Z2hZJVHc~A-`d6737jsvz=8%Tq#dhDhzN9q zc5TaHQ)du(eo=RLu~h1OZStOYYs?RFQ|CQ|Ax#wcPXOD3$Btx`T*?^y$dlv}+rC;S zp8C`0f4+pBdTm3#V|Nwk?YAF2S(Ag4tL~0Sp=l}peX&LMml^dZiN3(J&@vT7UBo!?HWlj&O zOcvvoDC~+e?(3Sn-qUjF%|WMDqJHV+=>j|rsn)?1E*vAu=ex&av5bI(lhbD6yC^IA z;z;d=8x+iscB=>KI&QOi(aS@&K6bs+e1&8G?wTc&w66d?1eA_8EpSPA_CAL1rHvg2 z1c$Hy&J_3DI4Z$%F0_QkPfH0q8#zWe3l+5c`U8y=;SDNh6$zqxeH-Lb>nxp{$Wk12Qv(Awj2 z$73ChqMSh?-(7B|6NRk%-O+g~@UFyo+DZxh?aITmD6u`BXF=IiiXeshi54?U3nYU~?unC34W5Y}bxQQ~;>;*N@fo(IJSzE1 zA*o4F9zB73**dpa&EU$Zezv6#RJFQi zXH%0!E|rKlA^365bPDN%9%H_dzC_rxIL{11h;jB0wL$5n^CqJ&V-0cj=6^v%)_4?Z zjt?~4&P0^L6ZH|J#EB(RWRu%oFUgL^dFRS3h_6~NQ9980l`s8mTY*aHofE0=LBs8Z z<%!;^x56%ohVGcO6g;Au_$K-mlfbIn@!dmjCKl|}*6I`CnU^^o!`HU8JgVX8YnUGJQG{bO1^@ zKAg>Pked!rh6lbPg57w^^DhD)qZux!zlG<9a?HL(Z(+kT;B975u}zA%NP2XBeC*U3m|!ze>ZXy z+!iiHCo;-<0Fn^Q5PoG&ZPhoa?_EIUB*YFU&D+or)RPtg&6qEjAK)#N9ns<8wZS08 z2pyBofe=O^3i+L%jPIRBZ4`c_-tR&en+P&guaY?Yv9yL+%>vu8BmMON~h)| z^7ksUJ~P)`?AmCnkSd%*ayEN?fbSZT3^AxzUHx5nca^4^m&5I&{ehgVg7ma#Cjj-y z{*k|!G*O;?sHJs`V{y!oPc?){oKr0~P+VUrB{Lx710*853@5wr6C9d8z!Hwm-{jNrXjdy%QU`{k%OUUj= zgR-*li9C2lrBcYe+cI4yV(~YWixVw4N%udoF^4p}M z@pIyh3j8b$l`6?mhEBGrg25?MCDvPxE0Wx|k)mH@f|lF(TxZR8=I=La96yn`dfY#5 zTcvRfrEN8K#64zSiyfOR*5K!?JIM1!?x=*kS^^v?mAI$9O#WFnDqCASW}#Prg1LWgPq+`X{y}n!2F|1j(2*Jhd+!&eK{Lej*%aqdg4%zrK)QyAjWt=<#eZy& zK;Hem^qj30s{jPHry-7KK$xfV8@R$vCmf4%(tPP~2MLBKb)#5Y#aRqYj^6|)R)vkx z`r~n7FtUO<#iQT1-K*Wg0_3Eh>PNmeuf^wnkjflwj7p}y z-@vK!j22=Tm-t@xRhqPKZr{JUL0AmK$VTX~ZMFT!7p@i63{ zj)rq$Av>_%lQoV%aXaw?+ltQT`@Jj%JgkzRdfm(IhI?0kKMmXusxMj|JG)q?g^nta_tkvmNcGoSi9 z0bE44=;rR7-O}zvW8ILlG~O(DCGz0eo`_kFBzgT9F2wYl!!Lfvetde%ei4Zgz>Wvh z!Qcz!B$o)nbbH3abt^jgj{^t$26)G~I7zICq{zHkYyIB-44WbrT0|x@06eS5PwVO* h-Mje=LK*U^+(q?FH?o_iF+2YfTgbW7sXMfy{T~cHx4-}Z diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json index 71e2d5bd05c95..a0f384a96e6b4 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json @@ -29,33 +29,3 @@ { "type": "doc", "value": { "id": "visualization:1bba55f0-507e-11eb-9c0d-97106882b997", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "search_0", "type": "search" } ], "type": "visualization", "updated_at": "2021-01-07T00:23:04.624Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" }, "savedSearchRefName": "search_0", "title": "Tag Cloud of Names", "uiStateJSON": "{}", "version": 1, "visState": "{\"title\":\"Tag Cloud of Names\",\"type\":\"tagcloud\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"customer_first_name.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true}}" } } } } { "type": "doc", "value": { "id": "ui-counter:DashboardPanelVersionInUrl:06012021:loaded:8.0.0", "index": ".kibana_1", "source": { "type": "ui-counter", "ui-counter": { "count": 85 }, "updated_at": "2021-01-07T00:23:25.741Z" } } } - -{ - "type": "doc", - "value": { - "id": "search:357825a0-8290-11eb-b8f1-15ed8d3eeaaf", - "index": ".kibana_1", - "source": { - "references": [ - { - "id": "5193f870-d861-11e9-a311-0fa548c5f953", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "search": { - "columns": [ "_id", "order_id", "geoip" ], - "description": "", - "hits": 0, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "sort": [ [ "order_date", "desc" ] ], - "title": "ECommerce - GEOIP Data", - "version": 1 - }, - "type": "search", - "updated_at": "2021-03-11T17:35:44.894Z" - } - } -} From 98f86409c9c8af49d895ad004af959fb2930e934 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 15:36:26 -0700 Subject: [PATCH 29/51] functional test fixes --- .../generate_csv/generate_csv.ts | 13 ++-- .../discover/__snapshots__/reporting.snap | 22 ++++-- .../functional/apps/discover/reporting.ts | 70 ++++++------------- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 1ea8243f43785..83330a310f1f5 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -143,10 +143,15 @@ export class CsvGenerator { }; } - private getFieldsFromSearchSource(searchSource: ISearchSource): SearchFieldValue[] { - let fields: string | boolean | SearchFieldValue[] | undefined = - searchSource.getField('fields') || searchSource.getField('fieldsFromSource'); + private getFields(searchSource: ISearchSource): SearchFieldValue[] { + const fieldValues: Record = { + fields: searchSource.getField('fields'), + fieldsFromSource: searchSource.getField('fieldsFromSource'), + }; + const fieldSource = fieldValues.fieldsFromSource ? 'fieldsFromSource' : 'fields'; + this.logger.info(`Getting search source fields from: '${fieldSource}'`); + let fields = fieldValues[fieldSource]; if (fields === true || typeof fields === 'string') { fields = [fields.toString()]; } @@ -345,7 +350,7 @@ export class CsvGenerator { // write the header and initialize formatters / column orderings // depends on the table to know what order to place the columns - const fields = this.getFieldsFromSearchSource(searchSource); + const fields = this.getFields(searchSource); if (first) { first = false; diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 728a2e1c42335..a5423ab229353 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,9 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`discover Discover Generate CSV: Fields From Source limitation With using fieldsFromSource, it generates a report that does not have GEOIP data 1`] = `"FIXME"`; - -exports[`discover Discover Generate CSV: Fields From Source limitation Without using fieldsFromSource, it generates a report with GEOIP data 1`] = `"FIXME"`; - exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" @@ -22,6 +18,24 @@ exports[`discover Discover Generate CSV: archived search generates a report with " `; +exports[`discover Discover Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +" +`; + exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 02eb4ab4a5ec3..10d48747a9b31 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -113,12 +113,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(() => PageObjects.common.navigateToApp('discover')); - it('generates a report with data', async () => { - await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + const setupPage = async () => { const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; const toTime = 'Aug 23, 2019 @ 16:18:51.821'; await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + }; + const getReport = async () => { await PageObjects.reporting.openCsvReportingPanel(); await PageObjects.reporting.clickGenerateReportButton(); @@ -127,64 +128,39 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(res.status).to.equal(200); expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - expectSnapshot(res.text).toMatch(); + return res; + }; + + it('generates a report with data', async () => { + await setupPage(); + await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + + const { text } = await getReport(); + expectSnapshot(text).toMatch(); }); it('generates a report with filtered data', async () => { + await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); - const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; - const toTime = 'Aug 23, 2019 @ 16:18:51.821'; - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); // filter and re-save await filterBar.addFilter('currency', 'is', 'EUR'); - await PageObjects.discover.saveSearch(`Ecommerce Data: EUR Filtered`); - - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); - - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); - - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - expectSnapshot(res.text).toMatch(); - }); - }); - - describe('Generate CSV: Fields From Source limitation', () => { - before(async () => { - await esArchiver.load('reporting/ecommerce'); - await esArchiver.load('reporting/ecommerce_kibana'); - }); - - after(async () => { - await esArchiver.unload('reporting/ecommerce'); - await esArchiver.unload('reporting/ecommerce_kibana'); - }); + await PageObjects.discover.saveSearch(`Ecommerce Data: EUR Filtered`); // renamed the search - afterEach(async () => { - await kibanaServer.uiSettings.replace({}); + const { text } = await getReport(); + expectSnapshot(text).toMatch(); + await PageObjects.discover.saveSearch(`Ecommerce Data`); // rename the search back for the next test }); - beforeEach(() => PageObjects.common.navigateToApp('discover')); + it('generates a report with discover:searchFieldsFromSource = true', async () => { + await setupPage(); + await PageObjects.discover.loadSavedSearch('Ecommerce Data'); - it('With using fieldsFromSource, it generates a report that does not have GEOIP data', async () => { await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': true }); - await PageObjects.discover.loadSavedSearch('ECommerce Data'); - const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; - const toTime = 'Aug 23, 2019 @ 16:18:51.821'; - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); + await browser.refresh(); - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); - - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - expectSnapshot(res.text).toMatch(); + const { text } = await getReport(); + expectSnapshot(text).toMatch(); }); }); }); From 5998a42270516c64c085fa68364b4c856695d348 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 15:57:40 -0700 Subject: [PATCH 30/51] clean up ecommerce test archive --- .../functional/apps/discover/reporting.ts | 6 +- .../reporting/ecommerce/data.json.gz | Bin 957893 -> 956882 bytes .../reporting/ecommerce/mappings.json | 1015 ----------------- .../reporting/ecommerce_kibana/data.json | 6 - 4 files changed, 3 insertions(+), 1024 deletions(-) diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 10d48747a9b31..b4602892f8c42 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -20,13 +20,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Discover', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); - // FIXME: should also use reporting/ecommerce_kibana - // reporting/ecommerce needs to have the kibana object cleared out - await esArchiver.loadIfNeeded('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); await browser.setWindowSize(1600, 850); }); after('clean up archives', async () => { await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); await es.deleteByQuery({ index: '.reporting-*', refresh: true, diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz b/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz index 7736287bc9a37e5203c887d89bcfbe7d98fe1dd9..e1710365c4b414dc0c0071e9a2317512580a625b 100644 GIT binary patch delta 58013 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 aYUPK@`ti!#h{gQ_LMGQ5w^2qL!v6rllKrRv diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce/mappings.json b/x-pack/test/functional/es_archives/reporting/ecommerce/mappings.json index 9e3275bd40bfe..6b474059a8e7a 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce/mappings.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce/mappings.json @@ -209,1018 +209,3 @@ } } } - -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "apm-telemetry": "07ee1939fa4302c62ddc052ec03fed90", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "config": "87aca8fdb053154f11383fce3dbf3edf", - "dashboard": "d00f614b29a80360e1190193fd333bab", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "66eccb05066c5a89924f48a9e9736499", - "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "map": "23d7aa4a720d4938ccde3983f87bd58d", - "maps-telemetry": "a4229f8b16a6820c6d724b7e0c1f729d", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "namespace": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "181661168bbadd1eff5902361e2a0d5c", - "server": "ec97f1c5da1a19609a60874e5af1100c", - "siem-ui-timeline": "1f6f0860ad7bc0dba3e42467ca40470d", - "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", - "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", - "space": "25de8c2deec044392922989cfcf24c54", - "telemetry": "e1c8bc94e443aefd9458932cc0697a4d", - "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "a53a20fe086b72c9a86da3cc12dad8a6", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "visualization": "52d7a13ad68a150c4525b292d23e12cc" - } - }, - "dynamic": "strict", - "properties": { - "apm-telemetry": { - "properties": { - "has_any_services": { - "type": "boolean" - }, - "services_per_agent": { - "properties": { - "dotnet": { - "null_value": 0, - "type": "long" - }, - "go": { - "null_value": 0, - "type": "long" - }, - "java": { - "null_value": 0, - "type": "long" - }, - "js-base": { - "null_value": 0, - "type": "long" - }, - "nodejs": { - "null_value": 0, - "type": "long" - }, - "python": { - "null_value": 0, - "type": "long" - }, - "ruby": { - "null_value": 0, - "type": "long" - }, - "rum-js": { - "null_value": 0, - "type": "long" - } - } - } - } - }, - "canvas-element": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "content": { - "type": "text" - }, - "help": { - "type": "text" - }, - "image": { - "type": "text" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "canvas-workpad": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "config": { - "dynamic": "true", - "properties": { - "buildNum": { - "type": "keyword" - }, - "dateFormat:tz": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "defaultIndex": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "dashboard": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "optionsJSON": { - "type": "text" - }, - "panelsJSON": { - "type": "text" - }, - "refreshInterval": { - "properties": { - "display": { - "type": "keyword" - }, - "pause": { - "type": "boolean" - }, - "section": { - "type": "integer" - }, - "value": { - "type": "integer" - } - } - }, - "timeFrom": { - "type": "keyword" - }, - "timeRestore": { - "type": "boolean" - }, - "timeTo": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "file-upload-telemetry": { - "properties": { - "filesUploadedTotalCount": { - "type": "long" - } - } - }, - "graph-workspace": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "numLinks": { - "type": "integer" - }, - "numVertices": { - "type": "integer" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "wsState": { - "type": "text" - } - } - }, - "index-pattern": { - "properties": { - "fieldFormatMap": { - "type": "text" - }, - "fields": { - "type": "text" - }, - "intervalName": { - "type": "keyword" - }, - "notExpandable": { - "type": "boolean" - }, - "sourceFilters": { - "type": "text" - }, - "timeFieldName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "type": { - "type": "keyword" - }, - "typeMeta": { - "type": "keyword" - } - } - }, - "infrastructure-ui-source": { - "properties": { - "description": { - "type": "text" - }, - "fields": { - "properties": { - "container": { - "type": "keyword" - }, - "host": { - "type": "keyword" - }, - "pod": { - "type": "keyword" - }, - "tiebreaker": { - "type": "keyword" - }, - "timestamp": { - "type": "keyword" - } - } - }, - "logAlias": { - "type": "keyword" - }, - "logColumns": { - "properties": { - "fieldColumn": { - "properties": { - "field": { - "type": "keyword" - }, - "id": { - "type": "keyword" - } - } - }, - "messageColumn": { - "properties": { - "id": { - "type": "keyword" - } - } - }, - "timestampColumn": { - "properties": { - "id": { - "type": "keyword" - } - } - } - }, - "type": "nested" - }, - "metricAlias": { - "type": "keyword" - }, - "name": { - "type": "text" - } - } - }, - "kql-telemetry": { - "properties": { - "optInCount": { - "type": "long" - }, - "optOutCount": { - "type": "long" - } - } - }, - "map": { - "properties": { - "bounds": { - "type": "geo_shape" - }, - "description": { - "type": "text" - }, - "layerListJSON": { - "type": "text" - }, - "mapStateJSON": { - "type": "text" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "maps-telemetry": { - "properties": { - "attributesPerMap": { - "properties": { - "dataSourcesCount": { - "properties": { - "avg": { - "type": "long" - }, - "max": { - "type": "long" - }, - "min": { - "type": "long" - } - } - }, - "emsVectorLayersCount": { - "dynamic": "true", - "type": "object" - }, - "layerTypesCount": { - "dynamic": "true", - "type": "object" - }, - "layersCount": { - "properties": { - "avg": { - "type": "long" - }, - "max": { - "type": "long" - }, - "min": { - "type": "long" - } - } - } - } - }, - "mapsTotalCount": { - "type": "long" - }, - "timeCaptured": { - "type": "date" - } - } - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "index-pattern": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "space": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "ml-telemetry": { - "properties": { - "file_data_visualizer": { - "properties": { - "index_creation_count": { - "type": "long" - } - } - } - } - }, - "namespace": { - "type": "keyword" - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "sample-data-telemetry": { - "properties": { - "installCount": { - "type": "long" - }, - "unInstallCount": { - "type": "long" - } - } - }, - "search": { - "properties": { - "columns": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "sort": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "server": { - "properties": { - "uuid": { - "type": "keyword" - } - } - }, - "siem-ui-timeline": { - "properties": { - "columns": { - "properties": { - "aggregatable": { - "type": "boolean" - }, - "category": { - "type": "keyword" - }, - "columnHeaderType": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "example": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "indexes": { - "type": "keyword" - }, - "name": { - "type": "text" - }, - "placeholder": { - "type": "text" - }, - "searchable": { - "type": "boolean" - }, - "type": { - "type": "keyword" - } - } - }, - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "dataProviders": { - "properties": { - "and": { - "properties": { - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - } - } - }, - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - } - } - }, - "dateRange": { - "properties": { - "end": { - "type": "date" - }, - "start": { - "type": "date" - } - } - }, - "description": { - "type": "text" - }, - "favorite": { - "properties": { - "favoriteDate": { - "type": "date" - }, - "fullName": { - "type": "text" - }, - "keySearch": { - "type": "text" - }, - "userName": { - "type": "text" - } - } - }, - "kqlMode": { - "type": "keyword" - }, - "kqlQuery": { - "properties": { - "filterQuery": { - "properties": { - "kuery": { - "properties": { - "expression": { - "type": "text" - }, - "kind": { - "type": "keyword" - } - } - }, - "serializedQuery": { - "type": "text" - } - } - } - } - }, - "sort": { - "properties": { - "columnId": { - "type": "keyword" - }, - "sortDirection": { - "type": "keyword" - } - } - }, - "title": { - "type": "text" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-note": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "note": { - "type": "text" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-pinned-event": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "space": { - "properties": { - "_reserved": { - "type": "boolean" - }, - "color": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "disabledFeatures": { - "type": "keyword" - }, - "initials": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "telemetry": { - "properties": { - "enabled": { - "type": "boolean" - } - } - }, - "timelion-sheet": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "timelion_chart_height": { - "type": "integer" - }, - "timelion_columns": { - "type": "integer" - }, - "timelion_interval": { - "type": "keyword" - }, - "timelion_other_interval": { - "type": "keyword" - }, - "timelion_rows": { - "type": "integer" - }, - "timelion_sheet": { - "type": "text" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "type": { - "type": "keyword" - }, - "ui-metric": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "updated_at": { - "type": "date" - }, - "upgrade-assistant-reindex-operation": { - "dynamic": "true", - "properties": { - "indexName": { - "type": "keyword" - }, - "status": { - "type": "integer" - } - } - }, - "upgrade-assistant-telemetry": { - "properties": { - "features": { - "properties": { - "deprecation_logging": { - "properties": { - "enabled": { - "null_value": true, - "type": "boolean" - } - } - } - } - }, - "ui_open": { - "properties": { - "cluster": { - "null_value": 0, - "type": "long" - }, - "indices": { - "null_value": 0, - "type": "long" - }, - "overview": { - "null_value": 0, - "type": "long" - } - } - }, - "ui_reindex": { - "properties": { - "close": { - "null_value": 0, - "type": "long" - }, - "open": { - "null_value": 0, - "type": "long" - }, - "start": { - "null_value": 0, - "type": "long" - }, - "stop": { - "null_value": 0, - "type": "long" - } - } - } - } - }, - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "savedSearchRefName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "type": "text" - } - } - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json index a0f384a96e6b4..2bead1ff8aec2 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json @@ -20,12 +20,6 @@ { "type": "doc", "value": { "id": "space:default", "index": ".kibana_1", "source": { "space": { "_reserved": true, "description": "This is the default space", "disabledFeatures": [ ], "name": "Default Space" }, "type": "space", "updated_at": "2021-01-07T00:17:12.785Z" } } } -{ "type": "doc", "value": { "id": "ui-counter:visualize:06012021:click:tagcloud", "index": ".kibana_1", "source": { "type": "ui-counter", "ui-counter": { "count": 1 }, "updated_at": "2021-01-07T00:18:52.592Z" } } } - -{ "type": "doc", "value": { "id": "ui-counter:data_plugin:06012021:click:discover:query_submitted", "index": ".kibana_1", "source": { "type": "ui-counter", "ui-counter": { "count": 1 }, "updated_at": "2021-01-07T00:18:52.592Z" } } } - { "type": "doc", "value": { "id": "dashboard:6c263e00-1c6d-11ea-a100-8589bb9d7c6b", "index": ".kibana_1", "source": { "dashboard": { "description": "", "hits": 0, "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" }, "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\"},\"panelIndex\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\"},\"panelIndex\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":35,\"w\":48,\"h\":18,\"i\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\"},\"panelIndex\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":48,\"h\":8,\"i\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\"},\"panelIndex\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":23,\"w\":16,\"h\":12,\"i\":\"a1e889dc-b80e-4937-a576-979f34d1859b\"},\"panelIndex\":\"a1e889dc-b80e-4937-a576-979f34d1859b\",\"embeddableConfig\":{\"enhancements\":{},\"vis\":null},\"panelRefName\":\"panel_4\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":16,\"y\":23,\"w\":12,\"h\":12,\"i\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\"},\"panelIndex\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":28,\"y\":23,\"w\":20,\"h\":12,\"i\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\"},\"panelIndex\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"}]", "refreshInterval": { "pause": true, "value": 0 }, "timeFrom": "2019-03-23T03:06:17.785Z", "timeRestore": true, "timeTo": "2019-10-04T02:33:16.708Z", "title": "Ecom Dashboard", "version": 1 }, "migrationVersion": { "dashboard": "7.11.0" }, "references": [ { "id": "0a464230-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_0", "type": "visualization" }, { "id": "200609c0-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_1", "type": "visualization" }, { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "panel_2", "type": "search" }, { "id": "4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_3", "type": "visualization" }, { "id": "ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", "name": "panel_4", "type": "visualization" }, { "id": "132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_5", "type": "visualization" }, { "id": "1bba55f0-507e-11eb-9c0d-97106882b997", "name": "panel_6", "type": "visualization" } ], "type": "dashboard", "updated_at": "2021-01-07T00:22:16.102Z" } } } { "type": "doc", "value": { "id": "visualization:1bba55f0-507e-11eb-9c0d-97106882b997", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "search_0", "type": "search" } ], "type": "visualization", "updated_at": "2021-01-07T00:23:04.624Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" }, "savedSearchRefName": "search_0", "title": "Tag Cloud of Names", "uiStateJSON": "{}", "version": 1, "visState": "{\"title\":\"Tag Cloud of Names\",\"type\":\"tagcloud\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"customer_first_name.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true}}" } } } } - -{ "type": "doc", "value": { "id": "ui-counter:DashboardPanelVersionInUrl:06012021:loaded:8.0.0", "index": ".kibana_1", "source": { "type": "ui-counter", "ui-counter": { "count": 85 }, "updated_at": "2021-01-07T00:23:25.741Z" } } } From 92b0013def4120fb103c09f03e4e9cec3474d81f Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 16:20:07 -0700 Subject: [PATCH 31/51] add test for new search with fieldsFromSource set --- .../application/helpers/get_sharing_data.ts | 26 +- .../discover/__snapshots__/reporting.snap | 14 +- .../functional/apps/discover/reporting.ts | 26 +- .../reporting/ecommerce_kibana/data.json | 444 +++++++++++++++++- 4 files changed, 478 insertions(+), 32 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 8b08004f41ad6..b63cd94618701 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -38,8 +38,6 @@ export async function getSharingData( searchSource.removeField('size'); // fields get re-set to match the saved search columns - searchSource.removeField('fields'); - searchSource.removeField('fieldsFromSource'); let columns = state.columns || []; // NOTE: A newly saved search with no columns selected will return a @@ -48,15 +46,16 @@ export async function getSharingData( columns = []; } - // conditionally add the time field column - let timeFieldName: string | undefined; - const hideTimeColumn = config.get(DOC_HIDE_TIME_COLUMN_SETTING); - if (!hideTimeColumn && index && index.timeFieldName) { - timeFieldName = index.timeFieldName; - } - - if (columns && columns.length > 0 && timeFieldName) { - columns = [timeFieldName, ...columns]; + if (columns && columns.length > 0) { + // conditionally add the time field column: + let timeFieldName: string | undefined; + const hideTimeColumn = config.get(DOC_HIDE_TIME_COLUMN_SETTING); + if (!hideTimeColumn && index && index.timeFieldName) { + timeFieldName = index.timeFieldName; + } + if (timeFieldName) { + columns = [timeFieldName, ...columns]; + } } // if search source uses fieldsFromSource, set that @@ -69,11 +68,6 @@ export async function getSharingData( }; } -/** - * makes getSharingData lazy loadable - */ -export function getSharingDataModule() {} - export interface DiscoverCapabilities { createShortUrl?: boolean; save?: boolean; diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index a5423ab229353..394d2100cb9ef 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -54,7 +54,19 @@ exports[`discover Discover Generate CSV: archived search generates a report with " `; -exports[`discover Discover Generate CSV: new search generates a report with data 1`] = ` +exports[`discover Discover Generate CSV: new search generates a report from a new search with data: default 1`] = ` +"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" +\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,,\\" - \\" +" +`; + +exports[`discover Discover Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` "\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" \\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ \\"\\"coordinates\\"\\": [ diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index b4602892f8c42..8511a5ac8374f 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -17,6 +17,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker']); const filterBar = getService('filterBar'); + const setFieldsFromSource = async (setValue: boolean) => { + await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue }); + }; + describe('Discover', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); @@ -67,7 +71,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); }); - it('generates a report with data', async () => { + it('generates a report from a new search with data: default', async () => { + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.reporting.setTimepickerInDataRange(); + await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); + await PageObjects.reporting.openCsvReportingPanel(); + await PageObjects.reporting.clickGenerateReportButton(); + + const url = await PageObjects.reporting.getReportURL(60000); + const res = await PageObjects.reporting.getResponse(url); + + expect(res.status).to.equal(200); + expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); + expectSnapshot(res.text).toMatch(); + }); + + it('generates a report from a new search with data: discover:searchFieldsFromSource', async () => { + await setFieldsFromSource(true); await PageObjects.discover.clickNewSearchButton(); await PageObjects.reporting.setTimepickerInDataRange(); await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); @@ -80,6 +100,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(res.status).to.equal(200); expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); expectSnapshot(res.text).toMatch(); + await setFieldsFromSource(false); }); it('generates a report with no data', async () => { @@ -156,11 +177,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); - await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': true }); + await setFieldsFromSource(true); await browser.refresh(); const { text } = await getReport(); expectSnapshot(text).toMatch(); + await setFieldsFromSource(false); }); }); }); diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json index 2bead1ff8aec2..5ed43beca98a3 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json @@ -1,25 +1,443 @@ -{ "type": "doc", "value": { "id": "config:7.0.0", "index": ".kibana_1", "source": { "config": { "buildNum": 9007199254740991, "dateFormat:tz": "UTC", "defaultIndex": "5193f870-d861-11e9-a311-0fa548c5f953" }, "migrationVersion": { "config": "7.13.0" }, "references": [ ], "type": "config", "updated_at": "2019-09-16T09:06:51.201Z" } } } +{ + "type": "doc", + "value": { + "id": "config:7.0.0", + "index": ".kibana_1", + "source": { + "config": { + "buildNum": 9007199254740991, + "dateFormat:tz": "UTC", + "defaultIndex": "5193f870-d861-11e9-a311-0fa548c5f953" + }, + "migrationVersion": { + "config": "7.13.0" + }, + "references": [], + "type": "config", + "updated_at": "2019-09-16T09:06:51.201Z" + } + } +} -{ "type": "doc", "value": { "id": "config:8.0.0", "index": ".kibana_1", "source": { "config": { "buildNum": 9007199254740991, "dateFormat:tz": "UTC", "defaultIndex": "5193f870-d861-11e9-a311-0fa548c5f953" }, "migrationVersion": { "config": "7.13.0" }, "references": [ ], "type": "config", "updated_at": "2019-12-11T23:22:12.698Z" } } } +{ + "type": "doc", + "value": { + "id": "config:8.0.0", + "index": ".kibana_1", + "source": { + "config": { + "buildNum": 9007199254740991, + "dateFormat:tz": "UTC", + "defaultIndex": "5193f870-d861-11e9-a311-0fa548c5f953" + }, + "migrationVersion": { + "config": "7.13.0" + }, + "references": [], + "type": "config", + "updated_at": "2019-12-11T23:22:12.698Z" + } + } +} -{ "type": "doc", "value": { "id": "index-pattern:5193f870-d861-11e9-a311-0fa548c5f953", "index": ".kibana_1", "source": { "index-pattern": { "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"category\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"category.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"category\"}}},{\"name\":\"currency\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_birth_date\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_first_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_first_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_first_name\"}}},{\"name\":\"customer_full_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_full_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_full_name\"}}},{\"name\":\"customer_gender\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_last_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_last_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_last_name\"}}},{\"name\":\"customer_phone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"day_of_week\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"day_of_week_i\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"manufacturer\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"manufacturer.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"manufacturer\"}}},{\"name\":\"order_date\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"order_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products._id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products._id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products._id\"}}},{\"name\":\"products.base_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.base_unit_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.category\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.category.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.category\"}}},{\"name\":\"products.created_on\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.discount_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.discount_percentage\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.manufacturer\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.manufacturer.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.manufacturer\"}}},{\"name\":\"products.min_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.product_id\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.product_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.product_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.product_name\"}}},{\"name\":\"products.quantity\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.sku\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.tax_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.taxful_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.taxless_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.unit_discount_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sku\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"taxful_total_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"taxless_total_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"total_quantity\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"total_unique_products\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", "timeFieldName": "order_date", "title": "ecommerce" }, "migrationVersion": { "index-pattern": "7.11.0" }, "references": [ ], "type": "index-pattern", "updated_at": "2019-12-11T23:24:13.381Z" } } } +{ + "type": "doc", + "value": { + "id": "index-pattern:5193f870-d861-11e9-a311-0fa548c5f953", + "index": ".kibana_1", + "source": { + "index-pattern": { + "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"category\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"category.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"category\"}}},{\"name\":\"currency\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_birth_date\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_first_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_first_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_first_name\"}}},{\"name\":\"customer_full_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_full_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_full_name\"}}},{\"name\":\"customer_gender\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"customer_last_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"customer_last_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"customer_last_name\"}}},{\"name\":\"customer_phone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"day_of_week\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"day_of_week_i\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"manufacturer\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"manufacturer.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"manufacturer\"}}},{\"name\":\"order_date\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"order_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products._id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products._id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products._id\"}}},{\"name\":\"products.base_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.base_unit_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.category\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.category.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.category\"}}},{\"name\":\"products.created_on\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.discount_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.discount_percentage\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.manufacturer\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.manufacturer.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.manufacturer\"}}},{\"name\":\"products.min_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.product_id\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.product_name\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"products.product_name.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"products.product_name\"}}},{\"name\":\"products.quantity\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.sku\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.tax_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.taxful_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.taxless_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"products.unit_discount_amount\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sku\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"taxful_total_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"taxless_total_price\",\"type\":\"number\",\"esTypes\":[\"half_float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"total_quantity\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"total_unique_products\",\"type\":\"number\",\"esTypes\":[\"integer\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", + "timeFieldName": "order_date", + "title": "ecommerce" + }, + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2019-12-11T23:24:13.381Z" + } + } +} -{ "type": "doc", "value": { "id": "search:6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "index": ".kibana_1", "source": { "migrationVersion": { "search": "7.9.3" }, "references": [ { "id": "5193f870-d861-11e9-a311-0fa548c5f953", "name": "kibanaSavedObjectMeta.searchSourceJSON.index", "type": "index-pattern" } ], "search": { "columns": [ "category", "currency", "customer_id", "order_id", "day_of_week_i", "order_date", "products.created_on", "sku" ], "description": "", "hits": 0, "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" }, "sort": [ [ "order_date", "desc" ] ], "title": "Ecommerce Data", "version": 1 }, "type": "search", "updated_at": "2019-12-11T23:24:28.540Z" } } } +{ + "type": "doc", + "value": { + "id": "search:6091ead0-1c6d-11ea-a100-8589bb9d7c6b", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "search": "7.9.3" + }, + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "search": { + "columns": [ + "products", + "geoip" + ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "order_date", + "desc" + ] + ], + "title": "Ecommerce Data", + "version": 1 + }, + "type": "search", + "updated_at": "2019-12-11T23:24:28.540Z" + } + } +} -{ "type": "doc", "value": { "id": "dashboard:constructed-sample-saved-object-id", "index": ".kibana_1", "source": { "dashboard": { "description": "", "hits": 0, "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" }, "optionsJSON": "{\"hidePanelTitles\":true,\"useMargins\":true}", "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\"},\"panelIndex\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\"},\"panelIndex\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":48,\"h\":18,\"i\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\"},\"panelIndex\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":33,\"w\":48,\"h\":8,\"i\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\"},\"panelIndex\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":41,\"w\":11,\"h\":10,\"i\":\"a1e889dc-b80e-4937-a576-979f34d1859b\"},\"panelIndex\":\"a1e889dc-b80e-4937-a576-979f34d1859b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":11,\"y\":41,\"w\":5,\"h\":10,\"i\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\"},\"panelIndex\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"}]", "refreshInterval": { "pause": true, "value": 0 }, "timeFrom": "2019-06-26T06:20:28.066Z", "timeRestore": true, "timeTo": "2019-06-26T07:27:58.573Z", "title": "Ecom Dashboard Hidden Panel Titles", "version": 1 }, "migrationVersion": { "dashboard": "7.11.0" }, "references": [ { "id": "0a464230-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_0", "type": "visualization" }, { "id": "200609c0-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_1", "type": "visualization" }, { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "panel_2", "type": "search" }, { "id": "4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_3", "type": "visualization" }, { "id": "ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", "name": "panel_4", "type": "visualization" }, { "id": "132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_5", "type": "visualization" } ], "type": "dashboard", "updated_at": "2020-04-10T00:37:48.462Z" } } } +{ + "type": "doc", + "value": { + "id": "dashboard:constructed-sample-saved-object-id", + "index": ".kibana_1", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" + }, + "optionsJSON": "{\"hidePanelTitles\":true,\"useMargins\":true}", + "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\"},\"panelIndex\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\"},\"panelIndex\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":48,\"h\":18,\"i\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\"},\"panelIndex\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":33,\"w\":48,\"h\":8,\"i\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\"},\"panelIndex\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":41,\"w\":11,\"h\":10,\"i\":\"a1e889dc-b80e-4937-a576-979f34d1859b\"},\"panelIndex\":\"a1e889dc-b80e-4937-a576-979f34d1859b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":11,\"y\":41,\"w\":5,\"h\":10,\"i\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\"},\"panelIndex\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"}]", + "refreshInterval": { + "pause": true, + "value": 0 + }, + "timeFrom": "2019-06-26T06:20:28.066Z", + "timeRestore": true, + "timeTo": "2019-06-26T07:27:58.573Z", + "title": "Ecom Dashboard Hidden Panel Titles", + "version": 1 + }, + "migrationVersion": { + "dashboard": "7.11.0" + }, + "references": [ + { + "id": "0a464230-79f0-11ea-ae7f-13c5d6e410a0", + "name": "panel_0", + "type": "visualization" + }, + { + "id": "200609c0-79f0-11ea-ae7f-13c5d6e410a0", + "name": "panel_1", + "type": "visualization" + }, + { + "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", + "name": "panel_2", + "type": "search" + }, + { + "id": "4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", + "name": "panel_3", + "type": "visualization" + }, + { + "id": "ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", + "name": "panel_4", + "type": "visualization" + }, + { + "id": "132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", + "name": "panel_5", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2020-04-10T00:37:48.462Z" + } + } +} -{ "type": "doc", "value": { "id": "visualization:0a464230-79f0-11ea-ae7f-13c5d6e410a0", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "5193f870-d861-11e9-a311-0fa548c5f953", "name": "kibanaSavedObjectMeta.searchSourceJSON.index", "type": "index-pattern" } ], "type": "visualization", "updated_at": "2020-04-08T23:24:05.971Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" }, "title": "e-commerce area chart", "uiStateJSON": "{}", "version": 1, "visState": "{\"type\":\"area\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"order_date\",\"timeRange\":{\"from\":\"2019-06-26T06:20:28.066Z\",\"to\":\"2019-06-26T07:27:58.573Z\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}],\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"labels\":{},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"title\":\"e-commerce area chart\"}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:0a464230-79f0-11ea-ae7f-13c5d6e410a0", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2020-04-08T23:24:05.971Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "e-commerce area chart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"type\":\"area\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"order_date\",\"timeRange\":{\"from\":\"2019-06-26T06:20:28.066Z\",\"to\":\"2019-06-26T07:27:58.573Z\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}],\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"labels\":{},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"title\":\"e-commerce area chart\"}" + } + } + } +} -{ "type": "doc", "value": { "id": "visualization:200609c0-79f0-11ea-ae7f-13c5d6e410a0", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "5193f870-d861-11e9-a311-0fa548c5f953", "name": "kibanaSavedObjectMeta.searchSourceJSON.index", "type": "index-pattern" } ], "type": "visualization", "updated_at": "2020-04-08T23:24:42.460Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" }, "title": "e-commerce pie chart", "uiStateJSON": "{}", "version": 1, "visState": "{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"order_date\",\"timeRange\":{\"from\":\"2019-06-26T06:20:28.066Z\",\"to\":\"2019-06-26T07:27:58.573Z\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100}},\"title\":\"e-commerce pie chart\"}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:200609c0-79f0-11ea-ae7f-13c5d6e410a0", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2020-04-08T23:24:42.460Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "e-commerce pie chart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"order_date\",\"timeRange\":{\"from\":\"2019-06-26T06:20:28.066Z\",\"to\":\"2019-06-26T07:27:58.573Z\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100}},\"title\":\"e-commerce pie chart\"}" + } + } + } +} -{ "type": "doc", "value": { "id": "visualization:ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "5193f870-d861-11e9-a311-0fa548c5f953", "name": "kibanaSavedObjectMeta.searchSourceJSON.index", "type": "index-pattern" } ], "type": "visualization", "updated_at": "2020-04-10T00:33:44.909Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}" }, "title": "게이지", "uiStateJSON": "{}", "version": 1, "visState": "{\"type\":\"gauge\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}],\"params\":{\"type\":\"gauge\",\"addTooltip\":true,\"addLegend\":true,\"isDisplayWarning\":false,\"gauge\":{\"alignment\":\"automatic\",\"extendRange\":true,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"colorsRange\":[{\"from\":0,\"to\":50},{\"from\":50,\"to\":75},{\"from\":75,\"to\":100}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":true,\"labels\":false,\"color\":\"rgba(105,112,125,0.2)\"},\"type\":\"meter\",\"style\":{\"bgWidth\":0.9,\"width\":0.9,\"mask\":false,\"bgMask\":false,\"maskBars\":50,\"bgFill\":\"rgba(105,112,125,0.2)\",\"bgColor\":true,\"subText\":\"\",\"fontSize\":60}}},\"title\":\"게이지\"}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2020-04-10T00:33:44.909Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}" + }, + "title": "게이지", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"type\":\"gauge\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}],\"params\":{\"type\":\"gauge\",\"addTooltip\":true,\"addLegend\":true,\"isDisplayWarning\":false,\"gauge\":{\"alignment\":\"automatic\",\"extendRange\":true,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"colorsRange\":[{\"from\":0,\"to\":50},{\"from\":50,\"to\":75},{\"from\":75,\"to\":100}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":true,\"labels\":false,\"color\":\"rgba(105,112,125,0.2)\"},\"type\":\"meter\",\"style\":{\"bgWidth\":0.9,\"width\":0.9,\"mask\":false,\"bgMask\":false,\"maskBars\":50,\"bgFill\":\"rgba(105,112,125,0.2)\",\"bgColor\":true,\"subText\":\"\",\"fontSize\":60}}},\"title\":\"게이지\"}" + } + } + } +} -{ "type": "doc", "value": { "id": "visualization:132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "5193f870-d861-11e9-a311-0fa548c5f953", "name": "kibanaSavedObjectMeta.searchSourceJSON.index", "type": "index-pattern" } ], "type": "visualization", "updated_at": "2020-04-10T00:34:44.700Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}" }, "title": "Українська", "uiStateJSON": "{}", "version": 1, "visState": "{\"type\":\"metric\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}],\"params\":{\"addTooltip\":true,\"addLegend\":false,\"type\":\"metric\",\"metric\":{\"percentageMode\":false,\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"metricColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"labels\":{\"show\":true},\"invertColors\":false,\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"title\":\"Українська\"}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [ + { + "id": "5193f870-d861-11e9-a311-0fa548c5f953", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2020-04-10T00:34:44.700Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\",\"filter\":[]}" + }, + "title": "Українська", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"type\":\"metric\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}],\"params\":{\"addTooltip\":true,\"addLegend\":false,\"type\":\"metric\",\"metric\":{\"percentageMode\":false,\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"metricColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"labels\":{\"show\":true},\"invertColors\":false,\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"title\":\"Українська\"}" + } + } + } +} -{ "type": "doc", "value": { "id": "visualization:4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ ], "type": "visualization", "updated_at": "2020-04-10T00:36:17.053Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" }, "title": "Tiểu thuyết", "uiStateJSON": "{}", "version": 1, "visState": "{\"type\":\"markdown\",\"aggs\":[],\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"Tiểu thuyết là một thể loại văn xuôi có hư cấu, thông qua nhân vật, hoàn cảnh, sự việc để phản ánh bức tranh xã hội rộng lớn và những vấn đề của cuộc sống con người, biểu hiện tính chất tường thuật, tính chất kể chuyện bằng ngôn ngữ văn xuôi theo những chủ đề xác định.\\n\\nTrong một cách hiểu khác, nhận định của Belinski: \\\"tiểu thuyết là sử thi của đời tư\\\" chỉ ra khái quát nhất về một dạng thức tự sự, trong đó sự trần thuật tập trung vào số phận của một cá nhân trong quá trình hình thành và phát triển của nó. Sự trần thuật ở đây được khai triển trong không gian và thời gian nghệ thuật đến mức đủ để truyền đạt cơ cấu của nhân cách[1].\\n\\n\\n[1]^ Mục từ Tiểu thuyết trong cuốn 150 thuật ngữ văn học, Lại Nguyên Ân biên soạn, Nhà xuất bản Đại học Quốc gia Hà Nội, in lần thứ 2 có sửa đổi bổ sung. H. 2003. Trang 326.\"},\"title\":\"Tiểu thuyết\"}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [], + "type": "visualization", + "updated_at": "2020-04-10T00:36:17.053Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "title": "Tiểu thuyết", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"type\":\"markdown\",\"aggs\":[],\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"Tiểu thuyết là một thể loại văn xuôi có hư cấu, thông qua nhân vật, hoàn cảnh, sự việc để phản ánh bức tranh xã hội rộng lớn và những vấn đề của cuộc sống con người, biểu hiện tính chất tường thuật, tính chất kể chuyện bằng ngôn ngữ văn xuôi theo những chủ đề xác định.\\n\\nTrong một cách hiểu khác, nhận định của Belinski: \\\"tiểu thuyết là sử thi của đời tư\\\" chỉ ra khái quát nhất về một dạng thức tự sự, trong đó sự trần thuật tập trung vào số phận của một cá nhân trong quá trình hình thành và phát triển của nó. Sự trần thuật ở đây được khai triển trong không gian và thời gian nghệ thuật đến mức đủ để truyền đạt cơ cấu của nhân cách[1].\\n\\n\\n[1]^ Mục từ Tiểu thuyết trong cuốn 150 thuật ngữ văn học, Lại Nguyên Ân biên soạn, Nhà xuất bản Đại học Quốc gia Hà Nội, in lần thứ 2 có sửa đổi bổ sung. H. 2003. Trang 326.\"},\"title\":\"Tiểu thuyết\"}" + } + } + } +} -{ "type": "doc", "value": { "id": "space:default", "index": ".kibana_1", "source": { "space": { "_reserved": true, "description": "This is the default space", "disabledFeatures": [ ], "name": "Default Space" }, "type": "space", "updated_at": "2021-01-07T00:17:12.785Z" } } } +{ + "type": "doc", + "value": { + "id": "space:default", + "index": ".kibana_1", + "source": { + "space": { + "_reserved": true, + "description": "This is the default space", + "disabledFeatures": [], + "name": "Default Space" + }, + "type": "space", + "updated_at": "2021-01-07T00:17:12.785Z" + } + } +} -{ "type": "doc", "value": { "id": "dashboard:6c263e00-1c6d-11ea-a100-8589bb9d7c6b", "index": ".kibana_1", "source": { "dashboard": { "description": "", "hits": 0, "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" }, "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\"},\"panelIndex\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\"},\"panelIndex\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":35,\"w\":48,\"h\":18,\"i\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\"},\"panelIndex\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":48,\"h\":8,\"i\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\"},\"panelIndex\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":23,\"w\":16,\"h\":12,\"i\":\"a1e889dc-b80e-4937-a576-979f34d1859b\"},\"panelIndex\":\"a1e889dc-b80e-4937-a576-979f34d1859b\",\"embeddableConfig\":{\"enhancements\":{},\"vis\":null},\"panelRefName\":\"panel_4\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":16,\"y\":23,\"w\":12,\"h\":12,\"i\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\"},\"panelIndex\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":28,\"y\":23,\"w\":20,\"h\":12,\"i\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\"},\"panelIndex\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"}]", "refreshInterval": { "pause": true, "value": 0 }, "timeFrom": "2019-03-23T03:06:17.785Z", "timeRestore": true, "timeTo": "2019-10-04T02:33:16.708Z", "title": "Ecom Dashboard", "version": 1 }, "migrationVersion": { "dashboard": "7.11.0" }, "references": [ { "id": "0a464230-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_0", "type": "visualization" }, { "id": "200609c0-79f0-11ea-ae7f-13c5d6e410a0", "name": "panel_1", "type": "visualization" }, { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "panel_2", "type": "search" }, { "id": "4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_3", "type": "visualization" }, { "id": "ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", "name": "panel_4", "type": "visualization" }, { "id": "132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", "name": "panel_5", "type": "visualization" }, { "id": "1bba55f0-507e-11eb-9c0d-97106882b997", "name": "panel_6", "type": "visualization" } ], "type": "dashboard", "updated_at": "2021-01-07T00:22:16.102Z" } } } +{ + "type": "doc", + "value": { + "id": "dashboard:6c263e00-1c6d-11ea-a100-8589bb9d7c6b", + "index": ".kibana_1", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" + }, + "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", + "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\"},\"panelIndex\":\"1c12c2f2-80c2-4d5c-b722-55b2415006e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\"},\"panelIndex\":\"1c4b99e1-7785-444f-a1c5-f592893b1a96\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":35,\"w\":48,\"h\":18,\"i\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\"},\"panelIndex\":\"94eab06f-60ac-4a85-b771-3a8ed475c9bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":48,\"h\":8,\"i\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\"},\"panelIndex\":\"52c19b6b-7117-42ac-a74e-c507a1c3ffc0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":23,\"w\":16,\"h\":12,\"i\":\"a1e889dc-b80e-4937-a576-979f34d1859b\"},\"panelIndex\":\"a1e889dc-b80e-4937-a576-979f34d1859b\",\"embeddableConfig\":{\"enhancements\":{},\"vis\":null},\"panelRefName\":\"panel_4\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":16,\"y\":23,\"w\":12,\"h\":12,\"i\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\"},\"panelIndex\":\"4930b035-d756-4cc5-9a18-1af9e67d6f31\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":28,\"y\":23,\"w\":20,\"h\":12,\"i\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\"},\"panelIndex\":\"55112375-d6f0-44f7-a8fb-867c8f7d464d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"}]", + "refreshInterval": { + "pause": true, + "value": 0 + }, + "timeFrom": "2019-03-23T03:06:17.785Z", + "timeRestore": true, + "timeTo": "2019-10-04T02:33:16.708Z", + "title": "Ecom Dashboard", + "version": 1 + }, + "migrationVersion": { + "dashboard": "7.11.0" + }, + "references": [ + { + "id": "0a464230-79f0-11ea-ae7f-13c5d6e410a0", + "name": "panel_0", + "type": "visualization" + }, + { + "id": "200609c0-79f0-11ea-ae7f-13c5d6e410a0", + "name": "panel_1", + "type": "visualization" + }, + { + "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", + "name": "panel_2", + "type": "search" + }, + { + "id": "4a36acd0-7ac3-11ea-b69c-cf0d7935cd67", + "name": "panel_3", + "type": "visualization" + }, + { + "id": "ef8757d0-7ac2-11ea-b69c-cf0d7935cd67", + "name": "panel_4", + "type": "visualization" + }, + { + "id": "132ab9c0-7ac3-11ea-b69c-cf0d7935cd67", + "name": "panel_5", + "type": "visualization" + }, + { + "id": "1bba55f0-507e-11eb-9c0d-97106882b997", + "name": "panel_6", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2021-01-07T00:22:16.102Z" + } + } +} -{ "type": "doc", "value": { "id": "visualization:1bba55f0-507e-11eb-9c0d-97106882b997", "index": ".kibana_1", "source": { "migrationVersion": { "visualization": "7.12.0" }, "references": [ { "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", "name": "search_0", "type": "search" } ], "type": "visualization", "updated_at": "2021-01-07T00:23:04.624Z", "visualization": { "description": "", "kibanaSavedObjectMeta": { "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" }, "savedSearchRefName": "search_0", "title": "Tag Cloud of Names", "uiStateJSON": "{}", "version": 1, "visState": "{\"title\":\"Tag Cloud of Names\",\"type\":\"tagcloud\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"customer_first_name.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true}}" } } } } +{ + "type": "doc", + "value": { + "id": "visualization:1bba55f0-507e-11eb-9c0d-97106882b997", + "index": ".kibana_1", + "source": { + "migrationVersion": { + "visualization": "7.12.0" + }, + "references": [ + { + "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", + "name": "search_0", + "type": "search" + } + ], + "type": "visualization", + "updated_at": "2021-01-07T00:23:04.624Z", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "savedSearchRefName": "search_0", + "title": "Tag Cloud of Names", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"Tag Cloud of Names\",\"type\":\"tagcloud\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"customer_first_name.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true}}" + } + } + } +} From b29672e1d5a8a4e9477d476041fe530bff0f1fad Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 11 Mar 2021 17:01:58 -0700 Subject: [PATCH 32/51] add tests and refactor tests --- .../application/helpers/get_sharing_data.ts | 9 +- .../generate_csv/generate_csv.ts | 136 +++----- .../discover/__snapshots__/reporting.snap | 94 +++--- .../functional/apps/discover/reporting.ts | 16 +- .../reporting/ecommerce_kibana/data.json | 10 +- .../csv_searchsource_immediate.snap | 292 ++++-------------- .../csv_searchsource_immediate.ts | 207 +++++++++---- 7 files changed, 310 insertions(+), 454 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index b63cd94618701..7518e0cf5e5e4 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -58,10 +58,11 @@ export async function getSharingData( } } - // if search source uses fieldsFromSource, set that - const fieldsKey = fields.fieldsFromSource ? 'fieldsFromSource' : 'fields'; - const fieldsValue = columns.length > 0 ? columns : ['*']; - searchSource.setField(fieldsKey, fieldsValue); + if (columns.length > 0) { + // if columns were selected in the saved search, use them for the searchSource's fields + const fieldsKey = fields.fieldsFromSource ? 'fieldsFromSource' : 'fields'; + searchSource.setField(fieldsKey, columns); + } return { searchSource: searchSource.getSerializedFields(true), diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 83330a310f1f5..d05f30923f8a2 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; import { IScopedSearchClient } from 'src/plugins/data/server'; -import { Datatable, DatatableColumn, DatatableRow } from 'src/plugins/expressions/server'; +import { Datatable, DatatableColumn } from 'src/plugins/expressions/server'; import { ReportingConfig } from '../../..'; import { ES_SEARCH_STRATEGY, @@ -19,7 +19,6 @@ import { IndexPattern, ISearchSource, ISearchStartSearchSource, - SearchFieldValue, tabifyDocs, } from '../../../../../../../src/plugins/data/common'; import { CancellationToken } from '../../../../common'; @@ -44,7 +43,6 @@ interface Dependencies { } export class CsvGenerator { - private _columnMap: number[] | null = null; private _formatters: Record | null = null; private csvContainsFormulas = false; private maxSizeReached = false; @@ -92,29 +90,6 @@ export class CsvGenerator { return results; } - /* - * Build a map for ordering the fields of search results into CSV columns - */ - private getColumnMap(fields: SearchFieldValue[] | undefined, table: Datatable) { - if (this._columnMap) { - return this._columnMap; - } - - // if there are selected fields, re-initialize columnMap with field order is set in searchSource fields - if (fields && fields[0] !== '*') { - this._columnMap = fields.map((field) => - table.columns.findIndex((column) => column.id === field) - ); - } - - // initialize default columnMap, works if fields are asterisk and order doesn't matter - if (!this._columnMap) { - this._columnMap = table.columns.map((c, columnIndex) => columnIndex); - } - - return this._columnMap; - } - /* * Load field formats for each field in the list */ @@ -143,63 +118,41 @@ export class CsvGenerator { }; } - private getFields(searchSource: ISearchSource): SearchFieldValue[] { - const fieldValues: Record = { - fields: searchSource.getField('fields'), - fieldsFromSource: searchSource.getField('fieldsFromSource'), - }; - const fieldSource = fieldValues.fieldsFromSource ? 'fieldsFromSource' : 'fields'; - this.logger.info(`Getting search source fields from: '${fieldSource}'`); - - let fields = fieldValues[fieldSource]; - if (fields === true || typeof fields === 'string') { - fields = [fields.toString()]; - } - if (fields == null) { - fields = ['undefined']; - } - if (!fields) { - fields = ['false']; - } - - return fields; - } + private formatCellValues(formatters: Record) { + return ({ + column: tableColumn, + data: dataTableCell, + }: { + column: DatatableColumn; + data: any; + }) => { + let cell: string[] | string; + // guard against _score, _type, etc + if (tableColumn && dataTableCell) { + try { + cell = formatters[tableColumn.id].convert(dataTableCell); + } catch (err) { + this.logger.error(err); + cell = '-'; + } - private getColumnName(fields: SearchFieldValue[] | undefined, table: Datatable) { - return (columnIndex: number, position: number) => { - let cell: string; - if (columnIndex > -1) { - cell = table.columns[columnIndex].name; - } else { - cell = fields && fields[position] ? (fields[position] as string) : 'unknown'; - } - return cell; - }; - } + try { + // expected values are a string of JSON where the value(s) is in an array + cell = JSON.parse(cell); + } catch (e) { + // ignore + } - private tryToParseCellValues( - formatters: Record, - dataTableRow: DatatableRow - ) { - return (tableColumn: DatatableColumn) => { - let cell: string[] | string = formatters[tableColumn.id].convert( - dataTableRow[tableColumn.id] - ); - - try { - // expected values are a string of JSON where the value(s) is in an array - cell = JSON.parse(cell); - } catch (e) { - // ignore - } + // We have to strip singular array values out of their array wrapper, + // So that the value appears the visually the same as seen in Discover + if (Array.isArray(cell)) { + cell = cell.join(', '); // mimic Discover behavior + } - // We have to strip singular array values out of their array wrapper, - // So that the value appears the visually the same as seen in Discover - if (Array.isArray(cell)) { - cell = cell.join(', '); // mimic Discover behavior + return cell; } - return cell; + return '-'; // Unknown field: it existed in searchSource but has no value in the result }; } @@ -207,19 +160,17 @@ export class CsvGenerator { * Use the list of fields to generate the header row */ private generateHeader( - fields: SearchFieldValue[] | undefined, table: Datatable, builder: MaxSizeStringBuilder, settings: CsvExportSettings ) { this.logger.debug(`Building CSV header row...`); - const columnMap = this.getColumnMap(fields, table); - const header = - columnMap - .map(this.getColumnName(fields, table)) + table.columns + .map((column) => column.name) + .map(settings.escapeValue) .map(this.checkForFormulas(settings)) - .join(settings.separator) + `\n`; + .join(settings.separator) + '\n'; if (!builder.tryAppend(header)) { return { @@ -235,24 +186,21 @@ export class CsvGenerator { * Format a Datatable into rows of CSV content */ private generateRows( - fields: SearchFieldValue[] | undefined, table: Datatable, builder: MaxSizeStringBuilder, formatters: Record, settings: CsvExportSettings ) { this.logger.debug(`Building ${table.rows.length} CSV data rows...`); - const columnMap = this.getColumnMap(fields, table); - for (const dataTableRow of table.rows) { if (this.cancellationToken.isCancelled()) { break; } const row = - columnMap - .map((columnIndex) => table.columns[columnIndex]) - .map(this.tryToParseCellValues(formatters, dataTableRow)) + table.columns + .map((c) => ({ column: c, data: dataTableRow[c.id] })) + .map(this.formatCellValues(formatters)) .map(this.checkForFormulas(settings)) .join(settings.separator) + '\n'; @@ -348,13 +296,9 @@ export class CsvGenerator { break; } - // write the header and initialize formatters / column orderings - // depends on the table to know what order to place the columns - const fields = this.getFields(searchSource); - if (first) { first = false; - this.generateHeader(fields, table, builder, settings); + this.generateHeader(table, builder, settings); } if (table.rows.length < 1) { @@ -362,7 +306,7 @@ export class CsvGenerator { } const formatters = this.getFormatters(table); - this.generateRows(fields, table, builder, formatters, settings); + this.generateRows(table, builder, formatters, settings); // update iterator currentRecord += table.rows.length; diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 394d2100cb9ef..0ea1fd5084988 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,79 +1,57 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" " `; exports[`discover Discover Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,currency,\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,geoip,manufacturer,\\"\\"\\"order_id\\"\\"\\",products,sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",591503,\\"[object Object], [object Object]\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",591709,\\"[object Object], [object Object]\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",590937,\\"[object Object], [object Object]\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",590976,\\"[object Object], [object Object]\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" " `; exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" " `; exports[`discover Discover Generate CSV: new search generates a report from a new search with data: default 1`] = ` -"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" -\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ - \\"\\"coordinates\\"\\": [ - 54.4, - 24.5 - ], - \\"\\"type\\"\\": \\"\\"Point\\"\\" -}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,,\\" - \\" +"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" " `; exports[`discover Discover Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` -"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" -\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ - \\"\\"coordinates\\"\\": [ - 54.4, - 24.5 - ], - \\"\\"type\\"\\": \\"\\"Point\\"\\" -}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,,\\" - \\" +"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" " `; diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 8511a5ac8374f..73258d712557a 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -25,7 +25,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); await esArchiver.load('reporting/ecommerce'); - await esArchiver.load('reporting/ecommerce_kibana'); await browser.setWindowSize(1600, 850); }); after('clean up archives', async () => { @@ -38,9 +37,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - describe('Generate CSV: new search', () => { - beforeEach(() => PageObjects.common.navigateToApp('discover')); - + describe('Check Available', () => { it('is not available if new', async () => { await PageObjects.reporting.openCsvReportingPanel(); expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true'); @@ -70,6 +67,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.reporting.openCsvReportingPanel(); expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); }); + }); + + describe('Generate CSV: new search', () => { + beforeEach(async () => { + await esArchiver.load('reporting/ecommerce_kibana'); // reload the archive to wipe out changes made by each test + await PageObjects.common.navigateToApp('discover'); + }); it('generates a report from a new search with data: default', async () => { await PageObjects.discover.clickNewSearchButton(); @@ -90,7 +94,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await setFieldsFromSource(true); await PageObjects.discover.clickNewSearchButton(); await PageObjects.reporting.setTimepickerInDataRange(); - await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); + await PageObjects.discover.saveSearch( + 'my search - with fieldsFromSource data - expectReportCanBeCreated' + ); await PageObjects.reporting.openCsvReportingPanel(); await PageObjects.reporting.clickGenerateReportButton(); diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json index 5ed43beca98a3..64d04ec6f49a9 100644 --- a/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json +++ b/x-pack/test/functional/es_archives/reporting/ecommerce_kibana/data.json @@ -79,8 +79,14 @@ ], "search": { "columns": [ - "products", - "geoip" + "order_date", + "category", + "currency", + "customer_id", + "order_id", + "day_of_week_i", + "products.created_on", + "sku" ], "description": "", "hits": 0, diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index f560a6c55ce9a..770a6701db5a7 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -1,251 +1,91 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Reporting APIs CSV generation from SearchSource date formatting Formatted date_nanos data, UTC timezone 1`] = ` -"date,message -\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\" -\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\" +exports[`Reporting APIs CSV Generation from SearchSource Settings set to fieldsFromSource Exports CSV with almost all selected fields when using fieldsFromSource 1`] = ` +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,currency,\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,geoip,manufacturer,\\"\\"\\"order_id\\"\\"\\",products,sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",591503,\\"[object Object], [object Object]\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",591709,\\"[object Object], [object Object]\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",590937,\\"[object Object], [object Object]\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",590976,\\"[object Object], [object Object]\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource date formatting Formatted date_nanos data, custom timezone (New York) 1`] = ` -"date,message -\\"Jan 1, 2015 @ 07:10:30.123456789\\",\\"Hello 2\\" -\\"Jan 1, 2015 @ 07:10:30.000000000\\",\\"Hello 1\\" +exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, UTC timezone 1`] = ` +"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" +\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, custom timezone (Phoenix) 1`] = ` -"\\"@timestamp\\",clientip,extension -\\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",jpg -\\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",jpg -\\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",jpg -\\"Sep 20, 2015 @ 03:26:45.468\\",\\"153.139.156.196\\",png -\\"Sep 20, 2015 @ 03:26:34.063\\",\\"25.140.171.133\\",css -\\"Sep 20, 2015 @ 03:26:11.181\\",\\"239.249.202.59\\",jpg -\\"Sep 20, 2015 @ 03:26:00.639\\",\\"95.59.225.31\\",css -\\"Sep 20, 2015 @ 03:26:00.094\\",\\"247.174.57.245\\",jpg -\\"Sep 20, 2015 @ 03:25:55.744\\",\\"116.126.47.226\\",css -\\"Sep 20, 2015 @ 03:25:54.701\\",\\"169.228.188.120\\",jpg -\\"Sep 20, 2015 @ 03:25:52.360\\",\\"74.224.77.232\\",css -\\"Sep 20, 2015 @ 03:25:49.913\\",\\"97.83.96.39\\",css -\\"Sep 20, 2015 @ 03:25:44.979\\",\\"175.188.44.145\\",css -\\"Sep 20, 2015 @ 03:25:40.968\\",\\"89.143.125.181\\",jpg -\\"Sep 20, 2015 @ 03:25:36.331\\",\\"231.169.195.137\\",css -\\"Sep 20, 2015 @ 03:25:34.064\\",\\"137.205.146.206\\",jpg -\\"Sep 20, 2015 @ 03:25:32.312\\",\\"53.0.188.251\\",jpg -\\"Sep 20, 2015 @ 03:25:27.254\\",\\"111.214.104.239\\",jpg -\\"Sep 20, 2015 @ 03:25:22.561\\",\\"111.46.85.146\\",jpg -\\"Sep 20, 2015 @ 03:25:06.674\\",\\"55.100.60.111\\",jpg -\\"Sep 20, 2015 @ 03:25:05.114\\",\\"34.197.178.155\\",jpg -\\"Sep 20, 2015 @ 03:24:55.114\\",\\"163.123.136.118\\",jpg -\\"Sep 20, 2015 @ 03:24:54.818\\",\\"11.195.163.57\\",jpg -\\"Sep 20, 2015 @ 03:24:53.742\\",\\"96.222.137.213\\",png -\\"Sep 20, 2015 @ 03:24:48.798\\",\\"227.228.214.218\\",jpg -\\"Sep 20, 2015 @ 03:24:20.223\\",\\"228.53.110.116\\",jpg -\\"Sep 20, 2015 @ 03:24:01.794\\",\\"196.131.253.111\\",png -\\"Sep 20, 2015 @ 03:23:49.521\\",\\"125.163.133.47\\",jpg -\\"Sep 20, 2015 @ 03:23:45.816\\",\\"148.47.216.255\\",jpg -\\"Sep 20, 2015 @ 03:23:36.052\\",\\"51.105.100.214\\",jpg -\\"Sep 20, 2015 @ 03:23:34.323\\",\\"41.210.252.157\\",gif -\\"Sep 20, 2015 @ 03:23:27.213\\",\\"248.163.75.193\\",png -\\"Sep 20, 2015 @ 03:23:14.866\\",\\"48.43.210.167\\",png -\\"Sep 20, 2015 @ 03:23:10.578\\",\\"33.95.78.209\\",css -\\"Sep 20, 2015 @ 03:23:07.001\\",\\"96.40.73.208\\",css -\\"Sep 20, 2015 @ 03:23:02.876\\",\\"174.32.230.63\\",jpg -\\"Sep 20, 2015 @ 03:23:00.019\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 03:22:47.447\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 03:22:45.803\\",\\"130.171.208.139\\",png -\\"Sep 20, 2015 @ 03:22:45.590\\",\\"39.250.210.253\\",jpg -\\"Sep 20, 2015 @ 03:22:43.997\\",\\"248.239.221.43\\",css -\\"Sep 20, 2015 @ 03:22:36.107\\",\\"232.64.207.109\\",gif -\\"Sep 20, 2015 @ 03:22:30.527\\",\\"24.186.122.118\\",jpg -\\"Sep 20, 2015 @ 03:22:25.697\\",\\"23.3.174.206\\",jpg -\\"Sep 20, 2015 @ 03:22:08.272\\",\\"185.170.80.142\\",php -\\"Sep 20, 2015 @ 03:21:40.822\\",\\"202.22.74.232\\",png -\\"Sep 20, 2015 @ 03:21:36.210\\",\\"39.227.27.167\\",jpg -\\"Sep 20, 2015 @ 03:21:19.154\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 03:21:09.852\\",\\"22.151.97.227\\",jpg -\\"Sep 20, 2015 @ 03:21:06.079\\",\\"157.39.25.197\\",css -\\"Sep 20, 2015 @ 03:21:01.357\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 03:20:56.519\\",\\"23.184.94.58\\",jpg -\\"Sep 20, 2015 @ 03:20:40.189\\",\\"80.83.92.252\\",jpg -\\"Sep 20, 2015 @ 03:20:27.012\\",\\"66.194.157.171\\",png -\\"Sep 20, 2015 @ 03:20:24.450\\",\\"15.191.218.38\\",jpg +exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, custom timezone (New York) 1`] = ` +"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jan 1, 2015 @ 07:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" +\\"Jan 1, 2015 @ 07:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, default to UTC 1`] = ` -"\\"@timestamp\\",clientip,extension -\\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg -\\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg -\\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg -\\"Sep 20, 2015 @ 10:26:45.468\\",\\"153.139.156.196\\",png -\\"Sep 20, 2015 @ 10:26:34.063\\",\\"25.140.171.133\\",css -\\"Sep 20, 2015 @ 10:26:11.181\\",\\"239.249.202.59\\",jpg -\\"Sep 20, 2015 @ 10:26:00.639\\",\\"95.59.225.31\\",css -\\"Sep 20, 2015 @ 10:26:00.094\\",\\"247.174.57.245\\",jpg -\\"Sep 20, 2015 @ 10:25:55.744\\",\\"116.126.47.226\\",css -\\"Sep 20, 2015 @ 10:25:54.701\\",\\"169.228.188.120\\",jpg -\\"Sep 20, 2015 @ 10:25:52.360\\",\\"74.224.77.232\\",css -\\"Sep 20, 2015 @ 10:25:49.913\\",\\"97.83.96.39\\",css -\\"Sep 20, 2015 @ 10:25:44.979\\",\\"175.188.44.145\\",css -\\"Sep 20, 2015 @ 10:25:40.968\\",\\"89.143.125.181\\",jpg -\\"Sep 20, 2015 @ 10:25:36.331\\",\\"231.169.195.137\\",css -\\"Sep 20, 2015 @ 10:25:34.064\\",\\"137.205.146.206\\",jpg -\\"Sep 20, 2015 @ 10:25:32.312\\",\\"53.0.188.251\\",jpg -\\"Sep 20, 2015 @ 10:25:27.254\\",\\"111.214.104.239\\",jpg -\\"Sep 20, 2015 @ 10:25:22.561\\",\\"111.46.85.146\\",jpg -\\"Sep 20, 2015 @ 10:25:06.674\\",\\"55.100.60.111\\",jpg -\\"Sep 20, 2015 @ 10:25:05.114\\",\\"34.197.178.155\\",jpg -\\"Sep 20, 2015 @ 10:24:55.114\\",\\"163.123.136.118\\",jpg -\\"Sep 20, 2015 @ 10:24:54.818\\",\\"11.195.163.57\\",jpg -\\"Sep 20, 2015 @ 10:24:53.742\\",\\"96.222.137.213\\",png -\\"Sep 20, 2015 @ 10:24:48.798\\",\\"227.228.214.218\\",jpg -\\"Sep 20, 2015 @ 10:24:20.223\\",\\"228.53.110.116\\",jpg -\\"Sep 20, 2015 @ 10:24:01.794\\",\\"196.131.253.111\\",png -\\"Sep 20, 2015 @ 10:23:49.521\\",\\"125.163.133.47\\",jpg -\\"Sep 20, 2015 @ 10:23:45.816\\",\\"148.47.216.255\\",jpg -\\"Sep 20, 2015 @ 10:23:36.052\\",\\"51.105.100.214\\",jpg -\\"Sep 20, 2015 @ 10:23:34.323\\",\\"41.210.252.157\\",gif -\\"Sep 20, 2015 @ 10:23:27.213\\",\\"248.163.75.193\\",png -\\"Sep 20, 2015 @ 10:23:14.866\\",\\"48.43.210.167\\",png -\\"Sep 20, 2015 @ 10:23:10.578\\",\\"33.95.78.209\\",css -\\"Sep 20, 2015 @ 10:23:07.001\\",\\"96.40.73.208\\",css -\\"Sep 20, 2015 @ 10:23:02.876\\",\\"174.32.230.63\\",jpg -\\"Sep 20, 2015 @ 10:23:00.019\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 10:22:47.447\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 10:22:45.803\\",\\"130.171.208.139\\",png -\\"Sep 20, 2015 @ 10:22:45.590\\",\\"39.250.210.253\\",jpg -\\"Sep 20, 2015 @ 10:22:43.997\\",\\"248.239.221.43\\",css -\\"Sep 20, 2015 @ 10:22:36.107\\",\\"232.64.207.109\\",gif -\\"Sep 20, 2015 @ 10:22:30.527\\",\\"24.186.122.118\\",jpg -\\"Sep 20, 2015 @ 10:22:25.697\\",\\"23.3.174.206\\",jpg -\\"Sep 20, 2015 @ 10:22:08.272\\",\\"185.170.80.142\\",php -\\"Sep 20, 2015 @ 10:21:40.822\\",\\"202.22.74.232\\",png -\\"Sep 20, 2015 @ 10:21:36.210\\",\\"39.227.27.167\\",jpg -\\"Sep 20, 2015 @ 10:21:19.154\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 10:21:09.852\\",\\"22.151.97.227\\",jpg -\\"Sep 20, 2015 @ 10:21:06.079\\",\\"157.39.25.197\\",css -\\"Sep 20, 2015 @ 10:21:01.357\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 10:20:56.519\\",\\"23.184.94.58\\",jpg -\\"Sep 20, 2015 @ 10:20:40.189\\",\\"80.83.92.252\\",jpg -\\"Sep 20, 2015 @ 10:20:27.012\\",\\"66.194.157.171\\",png -\\"Sep 20, 2015 @ 10:20:24.450\\",\\"15.191.218.38\\",jpg +exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, default to UTC 1`] = ` +"extension,\\"\\"\\"@timestamp\\"\\"\\",\\"\\"\\"utc_time\\"\\"\\",clientip,\\"\\"\\"relatedContent.article:modified_time\\"\\"\\",\\"\\"\\"relatedContent.article:published_time\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +jpg,\\"Sep 20, 2015 @ 10:26:48.725\\",\\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",\\"Jan 3, 2015 @ 16:26:58.000, Oct 28, 2014 @ 22:00:13.000, Nov 26, 2014 @ 01:19:52.000, Nov 26, 2014 @ 03:48:48.000, Nov 26, 2014 @ 02:36:20.000\\",\\"Mar 28, 2007 @ 00:03:55.000, Apr 11, 2008 @ 00:16:29.000, Feb 12, 2007 @ 20:02:30.000, Oct 19, 2005 @ 17:10:20.000, Jun 13, 2006 @ 21:06:38.000\\",\\"AU_x4AAaGFA8no6QjlMa\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 10:26:48.540\\",\\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",\\"Nov 26, 2014 @ 01:38:05.000, Nov 26, 2014 @ 01:40:12.000, Nov 27, 2014 @ 16:03:54.000, Nov 26, 2014 @ 01:17:50.000, Oct 28, 2014 @ 22:00:15.000\\",\\"Mar 22, 2006 @ 22:03:29.000, Apr 29, 2007 @ 20:04:15.000, Apr 14, 2008 @ 16:49:28.000, Oct 19, 2005 @ 17:10:56.000, Jun 5, 2008 @ 05:08:00.000\\",\\"AU_x3_g2GFA8no6QjjyV\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 10:26:48.353\\",\\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",\\"Nov 26, 2014 @ 04:41:33.000, Nov 27, 2014 @ 14:54:49.000\\",\\"May 11, 2006 @ 23:05:58.000, Mar 8, 2008 @ 14:00:00.000\\",\\"AU_x4AAZGFA8no6Qjk2z\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +png,\\"Sep 20, 2015 @ 10:26:45.468\\",\\"Sep 20, 2015 @ 10:26:45.468\\",\\"153.139.156.196\\",\\"Nov 27, 2014 @ 14:59:08.000, Nov 26, 2014 @ 02:18:38.000, Nov 27, 2014 @ 16:14:36.000, Nov 27, 2014 @ 00:15:19.000\\",\\"Sep 7, 2007 @ 00:40:28.000, Oct 17, 2005 @ 19:10:20.000, Dec 7, 2007 @ 15:00:42.000, Feb 5, 2008 @ 23:22:56.000\\",\\"AU_x4AAZGFA8no6Qjk5Y\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +css,\\"Sep 20, 2015 @ 10:26:34.063\\",\\"Sep 20, 2015 @ 10:26:34.063\\",\\"25.140.171.133\\",\\"Nov 27, 2014 @ 17:44:27.000, Nov 26, 2014 @ 02:55:44.000, Nov 27, 2014 @ 17:48:28.000, Nov 27, 2014 @ 18:43:09.000, Nov 26, 2014 @ 04:05:13.000\\",\\"Jul 12, 2007 @ 23:50:29.000, Jun 5, 2006 @ 20:06:32.000, Jun 9, 2008 @ 14:43:16.000, Dec 10, 2007 @ 15:47:00.000, Dec 18, 2007 @ 05:19:47.000\\",\\"AU_x3-TdGFA8no6QjiyL\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 10:26:11.181\\",\\"Sep 20, 2015 @ 10:26:11.181\\",\\"239.249.202.59\\",\\"Nov 26, 2014 @ 01:44:22.000, Apr 1, 2015 @ 16:01:40.000, Nov 27, 2014 @ 15:17:12.000, Nov 26, 2014 @ 01:24:00.000\\",\\"Feb 23, 2007 @ 01:02:07.000, Oct 19, 2007 @ 18:36:02.000, Aug 20, 2007 @ 02:33:32.000, Nov 13, 2006 @ 22:11:36.000\\",\\"AU_x3_BrGFA8no6QjjWt\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +css,\\"Sep 20, 2015 @ 10:26:00.639\\",\\"Sep 20, 2015 @ 10:26:00.639\\",\\"95.59.225.31\\",\\"Nov 26, 2014 @ 04:35:57.000\\",\\"Oct 23, 2005 @ 01:10:41.000\\",\\"AU_x3-TdGFA8no6Qji5N\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource date formatting With filters and timebased data, explicit UTC format 1`] = ` -"\\"@timestamp\\",clientip,extension -\\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg -\\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg -\\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg -\\"Sep 20, 2015 @ 10:26:45.468\\",\\"153.139.156.196\\",png -\\"Sep 20, 2015 @ 10:26:34.063\\",\\"25.140.171.133\\",css -\\"Sep 20, 2015 @ 10:26:11.181\\",\\"239.249.202.59\\",jpg -\\"Sep 20, 2015 @ 10:26:00.639\\",\\"95.59.225.31\\",css -\\"Sep 20, 2015 @ 10:26:00.094\\",\\"247.174.57.245\\",jpg -\\"Sep 20, 2015 @ 10:25:55.744\\",\\"116.126.47.226\\",css -\\"Sep 20, 2015 @ 10:25:54.701\\",\\"169.228.188.120\\",jpg -\\"Sep 20, 2015 @ 10:25:52.360\\",\\"74.224.77.232\\",css -\\"Sep 20, 2015 @ 10:25:49.913\\",\\"97.83.96.39\\",css -\\"Sep 20, 2015 @ 10:25:44.979\\",\\"175.188.44.145\\",css -\\"Sep 20, 2015 @ 10:25:40.968\\",\\"89.143.125.181\\",jpg -\\"Sep 20, 2015 @ 10:25:36.331\\",\\"231.169.195.137\\",css -\\"Sep 20, 2015 @ 10:25:34.064\\",\\"137.205.146.206\\",jpg -\\"Sep 20, 2015 @ 10:25:32.312\\",\\"53.0.188.251\\",jpg -\\"Sep 20, 2015 @ 10:25:27.254\\",\\"111.214.104.239\\",jpg -\\"Sep 20, 2015 @ 10:25:22.561\\",\\"111.46.85.146\\",jpg -\\"Sep 20, 2015 @ 10:25:06.674\\",\\"55.100.60.111\\",jpg -\\"Sep 20, 2015 @ 10:25:05.114\\",\\"34.197.178.155\\",jpg -\\"Sep 20, 2015 @ 10:24:55.114\\",\\"163.123.136.118\\",jpg -\\"Sep 20, 2015 @ 10:24:54.818\\",\\"11.195.163.57\\",jpg -\\"Sep 20, 2015 @ 10:24:53.742\\",\\"96.222.137.213\\",png -\\"Sep 20, 2015 @ 10:24:48.798\\",\\"227.228.214.218\\",jpg -\\"Sep 20, 2015 @ 10:24:20.223\\",\\"228.53.110.116\\",jpg -\\"Sep 20, 2015 @ 10:24:01.794\\",\\"196.131.253.111\\",png -\\"Sep 20, 2015 @ 10:23:49.521\\",\\"125.163.133.47\\",jpg -\\"Sep 20, 2015 @ 10:23:45.816\\",\\"148.47.216.255\\",jpg -\\"Sep 20, 2015 @ 10:23:36.052\\",\\"51.105.100.214\\",jpg -\\"Sep 20, 2015 @ 10:23:34.323\\",\\"41.210.252.157\\",gif -\\"Sep 20, 2015 @ 10:23:27.213\\",\\"248.163.75.193\\",png -\\"Sep 20, 2015 @ 10:23:14.866\\",\\"48.43.210.167\\",png -\\"Sep 20, 2015 @ 10:23:10.578\\",\\"33.95.78.209\\",css -\\"Sep 20, 2015 @ 10:23:07.001\\",\\"96.40.73.208\\",css -\\"Sep 20, 2015 @ 10:23:02.876\\",\\"174.32.230.63\\",jpg -\\"Sep 20, 2015 @ 10:23:00.019\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 10:22:47.447\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 10:22:45.803\\",\\"130.171.208.139\\",png -\\"Sep 20, 2015 @ 10:22:45.590\\",\\"39.250.210.253\\",jpg -\\"Sep 20, 2015 @ 10:22:43.997\\",\\"248.239.221.43\\",css -\\"Sep 20, 2015 @ 10:22:36.107\\",\\"232.64.207.109\\",gif -\\"Sep 20, 2015 @ 10:22:30.527\\",\\"24.186.122.118\\",jpg -\\"Sep 20, 2015 @ 10:22:25.697\\",\\"23.3.174.206\\",jpg -\\"Sep 20, 2015 @ 10:22:08.272\\",\\"185.170.80.142\\",php -\\"Sep 20, 2015 @ 10:21:40.822\\",\\"202.22.74.232\\",png -\\"Sep 20, 2015 @ 10:21:36.210\\",\\"39.227.27.167\\",jpg -\\"Sep 20, 2015 @ 10:21:19.154\\",\\"140.233.207.177\\",jpg -\\"Sep 20, 2015 @ 10:21:09.852\\",\\"22.151.97.227\\",jpg -\\"Sep 20, 2015 @ 10:21:06.079\\",\\"157.39.25.197\\",css -\\"Sep 20, 2015 @ 10:21:01.357\\",\\"37.127.124.65\\",jpg -\\"Sep 20, 2015 @ 10:20:56.519\\",\\"23.184.94.58\\",jpg -\\"Sep 20, 2015 @ 10:20:40.189\\",\\"80.83.92.252\\",jpg -\\"Sep 20, 2015 @ 10:20:27.012\\",\\"66.194.157.171\\",png -\\"Sep 20, 2015 @ 10:20:24.450\\",\\"15.191.218.38\\",jpg +exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, non-default timezone 1`] = ` +"extension,\\"\\"\\"@timestamp\\"\\"\\",\\"\\"\\"utc_time\\"\\"\\",clientip,\\"\\"\\"relatedContent.article:modified_time\\"\\"\\",\\"\\"\\"relatedContent.article:published_time\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +jpg,\\"Sep 20, 2015 @ 03:26:48.725\\",\\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",\\"Jan 3, 2015 @ 09:26:58.000, Oct 28, 2014 @ 15:00:13.000, Nov 25, 2014 @ 18:19:52.000, Nov 25, 2014 @ 20:48:48.000, Nov 25, 2014 @ 19:36:20.000\\",\\"Mar 27, 2007 @ 17:03:55.000, Apr 10, 2008 @ 17:16:29.000, Feb 12, 2007 @ 13:02:30.000, Oct 19, 2005 @ 10:10:20.000, Jun 13, 2006 @ 14:06:38.000\\",\\"AU_x4AAaGFA8no6QjlMa\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 03:26:48.540\\",\\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",\\"Nov 25, 2014 @ 18:38:05.000, Nov 25, 2014 @ 18:40:12.000, Nov 27, 2014 @ 09:03:54.000, Nov 25, 2014 @ 18:17:50.000, Oct 28, 2014 @ 15:00:15.000\\",\\"Mar 22, 2006 @ 15:03:29.000, Apr 29, 2007 @ 13:04:15.000, Apr 14, 2008 @ 09:49:28.000, Oct 19, 2005 @ 10:10:56.000, Jun 4, 2008 @ 22:08:00.000\\",\\"AU_x3_g2GFA8no6QjjyV\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 03:26:48.353\\",\\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",\\"Nov 25, 2014 @ 21:41:33.000, Nov 27, 2014 @ 07:54:49.000\\",\\"May 11, 2006 @ 16:05:58.000, Mar 8, 2008 @ 07:00:00.000\\",\\"AU_x4AAZGFA8no6Qjk2z\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +png,\\"Sep 20, 2015 @ 03:26:45.468\\",\\"Sep 20, 2015 @ 03:26:45.468\\",\\"153.139.156.196\\",\\"Nov 27, 2014 @ 07:59:08.000, Nov 25, 2014 @ 19:18:38.000, Nov 27, 2014 @ 09:14:36.000, Nov 26, 2014 @ 17:15:19.000\\",\\"Sep 6, 2007 @ 17:40:28.000, Oct 17, 2005 @ 12:10:20.000, Dec 7, 2007 @ 08:00:42.000, Feb 5, 2008 @ 16:22:56.000\\",\\"AU_x4AAZGFA8no6Qjk5Y\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +css,\\"Sep 20, 2015 @ 03:26:34.063\\",\\"Sep 20, 2015 @ 03:26:34.063\\",\\"25.140.171.133\\",\\"Nov 27, 2014 @ 10:44:27.000, Nov 25, 2014 @ 19:55:44.000, Nov 27, 2014 @ 10:48:28.000, Nov 27, 2014 @ 11:43:09.000, Nov 25, 2014 @ 21:05:13.000\\",\\"Jul 12, 2007 @ 16:50:29.000, Jun 5, 2006 @ 13:06:32.000, Jun 9, 2008 @ 07:43:16.000, Dec 10, 2007 @ 08:47:00.000, Dec 17, 2007 @ 22:19:47.000\\",\\"AU_x3-TdGFA8no6QjiyL\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +jpg,\\"Sep 20, 2015 @ 03:26:11.181\\",\\"Sep 20, 2015 @ 03:26:11.181\\",\\"239.249.202.59\\",\\"Nov 25, 2014 @ 18:44:22.000, Apr 1, 2015 @ 09:01:40.000, Nov 27, 2014 @ 08:17:12.000, Nov 25, 2014 @ 18:24:00.000\\",\\"Feb 22, 2007 @ 18:02:07.000, Oct 19, 2007 @ 11:36:02.000, Aug 19, 2007 @ 19:33:32.000, Nov 13, 2006 @ 15:11:36.000\\",\\"AU_x3_BrGFA8no6QjjWt\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +css,\\"Sep 20, 2015 @ 03:26:00.639\\",\\"Sep 20, 2015 @ 03:26:00.639\\",\\"95.59.225.31\\",\\"Nov 25, 2014 @ 21:35:57.000\\",\\"Oct 22, 2005 @ 18:10:41.000\\",\\"AU_x3-TdGFA8no6Qji5N\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource non-timebased Handle _id and _index columns 1`] = ` -"date,message,\\"_id\\",\\"_index\\" -\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos -\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos +exports[`Reporting APIs CSV Generation from SearchSource non-timebased Handle _id and _index columns 1`] = ` +"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" +\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource non-timebased With filters and non-timebased data 1`] = ` -"name,power -\\"Jonelle-Jane Marth\\",1 -\\"Suzie-May Rishel\\",1 -\\"Suzie-May Rishel\\",2 -\\"Rosana Casto\\",2 -\\"Stephen Cortez\\",4 -\\"Jonelle-Jane Marth\\",6 -\\"Jonelle-Jane Marth\\",7 -\\"Florinda Alejandro\\",10 -\\"Jonelle-Jane Marth\\",14 -\\"Suzie-May Rishel\\",19 -\\"Suzie-May Rishel\\",20 -\\"Florinda Alejandro\\",22 +exports[`Reporting APIs CSV Generation from SearchSource non-timebased With filters and non-timebased data 1`] = ` +"name,\\"\\"\\"@date\\"\\"\\",power,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jonelle-Jane Marth\\",\\"Feb 11, 2019 @ 03:21:31.000\\",1,UuEOUGkBxhhfVX4mK8ae,sales,\\"-\\",\\"-\\" +\\"Suzie-May Rishel\\",\\"Dec 4, 2018 @ 16:51:31.000\\",1,WOEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Suzie-May Rishel\\",\\"Jan 7, 2019 @ 22:06:31.000\\",2,VeEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Rosana Casto\\",\\"Apr 20, 2018 @ 13:51:31.000\\",2,bOEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Stephen Cortez\\",\\"Aug 1, 2018 @ 05:36:31.000\\",4,\\"Y-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" +\\"Jonelle-Jane Marth\\",\\"Mar 28, 2018 @ 18:21:31.000\\",6,buEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Jonelle-Jane Marth\\",\\"Sep 27, 2018 @ 06:21:31.000\\",7,XuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Florinda Alejandro\\",\\"Aug 12, 2018 @ 15:21:31.000\\",10,YuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Jonelle-Jane Marth\\",\\"Jun 16, 2018 @ 14:36:31.000\\",14,\\"Z-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" +\\"Suzie-May Rishel\\",\\"Mar 17, 2018 @ 08:36:31.000\\",19,\\"b-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" +\\"Suzie-May Rishel\\",\\"Jun 28, 2018 @ 00:21:31.000\\",20,ZuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +\\"Florinda Alejandro\\",\\"May 13, 2018 @ 09:21:31.000\\",22,auEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" " `; -exports[`Reporting APIs CSV generation from SearchSource validation Searches "huge" data, stops at Max Size Reached 1`] = ` -"\\"_id\\",date,name,gender,value,year,\\"years_ago\\",\\"date_informal\\" -\\"1984-Fiff-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fiff,F,5,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Filal-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Filal,F,15,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fillie-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fillie,F,135,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fillyjack-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fillyjack,F,6,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fing-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fing,F,6,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Firan-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Firan,F,9,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fishara-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fishara,F,5,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fishop-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fishop,F,9,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fj-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fj,F,12,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fjorn-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fjorn,F,22,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Flaine-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Flaine,F,234,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Flake-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Flake,F,420,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Flas-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Flas,F,38,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fo-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fo,F,45,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Foaz-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Foaz,F,13,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fob-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fob,F,170,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fobby-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fobby,F,\\"2,791\\",1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fodie-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fodie,F,12,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Foe-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Foe,F,15,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fomani-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fomani,F,7,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Ferley-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Ferley,F,6,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fernardino-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fernardino,F,30,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fernardo-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fernardo,F,115,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fernerd-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fernerd,F,6,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fernice-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fernice,F,7,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Ferry-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Ferry,F,47,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" -\\"1984-Fert-F\\",\\"Jan 1, 1984 @ 00:00:00.000\\",Fert,F,140,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" +exports[`Reporting APIs CSV Generation from SearchSource validation Searches large amount of data, stops at Max Size Reached 1`] = ` +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" " `; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts index 7f2a13b7cfe45..7cd09f2d8a293 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts @@ -31,7 +31,7 @@ export default function ({ getService }: FtrProviderContext) { }, }; - describe('CSV generation from SearchSource', () => { + describe('CSV Generation from SearchSource', () => { before(async () => { await kibanaServer.uiSettings.update({ 'csv:quoteValues': false, @@ -43,53 +43,124 @@ export default function ({ getService }: FtrProviderContext) { await reportingAPI.deleteAllReports(); }); - describe('date formatting', () => { - before(async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/logs'); - await esArchiver.load('logstash_functional'); - }); - after(async () => { - await esArchiver.unload('reporting/logs'); - await esArchiver.unload('logstash_functional'); - }); + describe('Settings set to fieldsFromSource', () => { + it('Exports CSV with almost all selected fields when using fieldsFromSource', async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); - it('With filters and timebased data, explicit UTC format', async () => { - const res = (await generateAPI.getCSVFromSearchSource( + const { + status: resStatus, + text: resText, + type: resType, + } = (await generateAPI.getCSVFromSearchSource( getMockJobParams({ - browserTimezone: 'UTC', searchSource: { - fields: ['@timestamp', 'clientip', 'extension'], - filter: [ - { - range: { - '@timestamp': { - gte: '2015-09-20T10:19:40.307Z', - lt: '2015-09-20T10:26:56.221Z', - }, - }, - }, - { - range: { - '@timestamp': { - format: 'strict_date_optional_time', - gte: '2015-01-12T07:00:55.654Z', - lte: '2016-01-29T21:08:10.881Z', + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], + fieldsFromSource: [ + '_id', + '_index', + '_score', + '_source', + '_type', + 'category', + 'category.keyword', + 'currency', + 'customer_birth_date', + 'customer_first_name', + 'customer_first_name.keyword', + 'customer_full_name', + 'customer_full_name.keyword', + 'customer_gender', + 'customer_id', + 'customer_last_name', + 'customer_last_name.keyword', + 'customer_phone', + 'day_of_week', + 'day_of_week_i', + 'email', + 'geoip.city_name', + 'geoip.continent_name', + 'geoip.country_iso_code', + 'geoip.location', + 'geoip.region_name', + 'manufacturer', + 'manufacturer.keyword', + 'order_date', + 'order_id', + 'products._id', + 'products._id.keyword', + 'products.base_price', + 'products.base_unit_price', + 'products.category', + 'products.category.keyword', + 'products.created_on', + 'products.discount_amount', + 'products.discount_percentage', + 'products.manufacturer', + 'products.manufacturer.keyword', + 'products.min_price', + 'products.price', + 'products.product_id', + 'products.product_name', + 'products.product_name.keyword', + 'products.quantity', + 'products.sku', + 'products.tax_amount', + 'products.taxful_price', + 'products.taxless_price', + 'products.unit_discount_amount', + 'sku', + 'taxful_total_price', + 'taxless_total_price', + 'total_quantity', + 'total_unique_products', + 'type', + 'user', + ], + filter: [], + parent: { + query: { language: 'kuery', query: '' }, + filter: [], + parent: { + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: '2019-03-23T03:06:17.785Z', + lte: '2019-10-04T02:33:16.708Z', + format: 'strict_date_optional_time', + }, + }, }, - }, + ], }, - ], - index: 'logstash-*', - query: { language: 'kuery', query: '' }, - sort: [{ '@timestamp': 'desc' }], + }, }, + browserTimezone: 'UTC', + title: 'testfooyu78yt90-', }) )) as supertest.Response; - const { status: resStatus, text: resText, type: resType } = res; - expect(resStatus).to.eql(200); expect(resType).to.eql('text/csv'); expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); + }); + + describe('date formatting', () => { + before(async () => { + // load test data that contains a saved search and documents + await esArchiver.load('reporting/logs'); + await esArchiver.load('logstash_functional'); + }); + after(async () => { + await esArchiver.unload('reporting/logs'); + await esArchiver.unload('logstash_functional'); }); it('With filters and timebased data, default to UTC', async () => { @@ -129,7 +200,7 @@ export default function ({ getService }: FtrProviderContext) { expectSnapshot(resText).toMatch(); }); - it('With filters and timebased data, custom timezone (Phoenix)', async () => { + it('With filters and timebased data, non-default timezone', async () => { const res = (await generateAPI.getCSVFromSearchSource( getMockJobParams({ browserTimezone: 'America/Phoenix', @@ -292,9 +363,9 @@ export default function ({ getService }: FtrProviderContext) { expect(body).to.eql(expectedBody); }); - it(`Searches "huge" data, stops at Max Size Reached`, async () => { - // load test data that contains a saved search and documents - await esArchiver.load('reporting/hugedata'); + it(`Searches large amount of data, stops at Max Size Reached`, async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); const { status: resStatus, @@ -303,33 +374,42 @@ export default function ({ getService }: FtrProviderContext) { } = (await generateAPI.getCSVFromSearchSource( getMockJobParams({ searchSource: { - query: { query: '', language: 'lucene' }, version: true, - sort: [{ date: 'desc' }], - index: '89655130-5013-11e9-bce7-4dabcb8bef24', + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], fields: [ - '_id', - 'date', - 'name', - 'gender', - 'value', - 'year', - 'years_ago', - 'date_informal', + 'order_date', + 'category', + 'currency', + 'customer_id', + 'order_id', + 'day_of_week_i', + 'products.created_on', + 'sku', ], - filter: [ - { - meta: { index: '89655130-5013-11e9-bce7-4dabcb8bef24', params: {} }, - range: { - date: { - gte: '1960-01-01T10:00:00Z', - lte: '1999-01-01T10:00:00Z', - format: 'strict_date_optional_time', + filter: [], + parent: { + query: { language: 'kuery', query: '' }, + filter: [], + parent: { + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: '2019-03-23T03:06:17.785Z', + lte: '2019-10-04T02:33:16.708Z', + format: 'strict_date_optional_time', + }, + }, }, - }, + ], }, - ], + }, }, + browserTimezone: 'UTC', + title: 'Ecommerce Data', }) )) as supertest.Response; @@ -337,7 +417,8 @@ export default function ({ getService }: FtrProviderContext) { expect(resType).to.eql('text/csv'); expectSnapshot(resText).toMatch(); - await esArchiver.unload('reporting/hugedata'); + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); }); }); }); From ae26fea1e57bc5061a8a5c43c3660e29018433b3 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 12 Mar 2021 10:37:41 -0700 Subject: [PATCH 33/51] cleanup redundant conditionals --- .../discover/public/application/helpers/get_sharing_data.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 7518e0cf5e5e4..de9d782c004fd 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -56,9 +56,7 @@ export async function getSharingData( if (timeFieldName) { columns = [timeFieldName, ...columns]; } - } - if (columns.length > 0) { // if columns were selected in the saved search, use them for the searchSource's fields const fieldsKey = fields.fieldsFromSource ? 'fieldsFromSource' : 'fields'; searchSource.setField(fieldsKey, columns); From d6699a2c77dd89b5348bd27d5ffc5c9b8d02455f Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 12 Mar 2021 10:37:57 -0700 Subject: [PATCH 34/51] add GenerateCsv.getFields --- .../generate_csv/generate_csv.ts | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index d05f30923f8a2..2eb766f9166aa 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; import { IScopedClusterClient, IUiSettingsClient } from 'src/core/server'; import { IScopedSearchClient } from 'src/plugins/data/server'; -import { Datatable, DatatableColumn } from 'src/plugins/expressions/server'; +import { Datatable } from 'src/plugins/expressions/server'; import { ReportingConfig } from '../../..'; import { ES_SEARCH_STRATEGY, @@ -19,6 +19,7 @@ import { IndexPattern, ISearchSource, ISearchStartSearchSource, + SearchFieldValue, tabifyDocs, } from '../../../../../../../src/plugins/data/common'; import { CancellationToken } from '../../../../common'; @@ -118,19 +119,31 @@ export class CsvGenerator { }; } + // use fields/fieldsFromSource from the searchSource to get the ordering of columns + // otherwise use the table columns as they are + private getFields(searchSource: ISearchSource, table: Datatable): string[] { + const fieldValues: Record = { + fields: searchSource.getField('fields'), + fieldsFromSource: searchSource.getField('fieldsFromSource'), + }; + const fieldSource = fieldValues.fieldsFromSource ? 'fieldsFromSource' : 'fields'; + this.logger.info(`Getting search source fields from: '${fieldSource}'`); + + let fields = fieldValues[fieldSource]; + if (!fields || fields === true || typeof fields === 'string') { + fields = table.columns.map((c) => c.id); + } + + return fields as string[]; // FIXME: fix TS + } + private formatCellValues(formatters: Record) { - return ({ - column: tableColumn, - data: dataTableCell, - }: { - column: DatatableColumn; - data: any; - }) => { + return ({ column: tableColumn, data: dataTableCell }: { column: string; data: any }) => { let cell: string[] | string; // guard against _score, _type, etc if (tableColumn && dataTableCell) { try { - cell = formatters[tableColumn.id].convert(dataTableCell); + cell = formatters[tableColumn].convert(dataTableCell); } catch (err) { this.logger.error(err); cell = '-'; @@ -160,14 +173,14 @@ export class CsvGenerator { * Use the list of fields to generate the header row */ private generateHeader( + fields: string[], table: Datatable, builder: MaxSizeStringBuilder, settings: CsvExportSettings ) { this.logger.debug(`Building CSV header row...`); const header = - table.columns - .map((column) => column.name) + fields .map(settings.escapeValue) .map(this.checkForFormulas(settings)) .join(settings.separator) + '\n'; @@ -186,6 +199,7 @@ export class CsvGenerator { * Format a Datatable into rows of CSV content */ private generateRows( + fields: string[], table: Datatable, builder: MaxSizeStringBuilder, formatters: Record, @@ -198,8 +212,8 @@ export class CsvGenerator { } const row = - table.columns - .map((c) => ({ column: c, data: dataTableRow[c.id] })) + fields + .map((f) => ({ column: f, data: dataTableRow[f] })) .map(this.formatCellValues(formatters)) .map(this.checkForFormulas(settings)) .join(settings.separator) + '\n'; @@ -296,9 +310,11 @@ export class CsvGenerator { break; } + const fields = this.getFields(searchSource, table); + if (first) { first = false; - this.generateHeader(table, builder, settings); + this.generateHeader(fields, table, builder, settings); } if (table.rows.length < 1) { @@ -306,7 +322,7 @@ export class CsvGenerator { } const formatters = this.getFormatters(table); - this.generateRows(table, builder, formatters, settings); + this.generateRows(fields, table, builder, formatters, settings); // update iterator currentRecord += table.rows.length; From 766cb85018fb905f30365039d62e3c2a654dd516 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 12 Mar 2021 10:46:59 -0700 Subject: [PATCH 35/51] fix some tests --- .../generate_csv/generate_csv.ts | 3 +- .../discover/__snapshots__/reporting.snap | 76 +++--- .../csv_searchsource_immediate.snap | 219 +++++++++++----- .../csv_searchsource_immediate.ts | 245 +++++++++++------- 4 files changed, 349 insertions(+), 194 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 2eb766f9166aa..fead01caa2959 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -130,7 +130,8 @@ export class CsvGenerator { this.logger.info(`Getting search source fields from: '${fieldSource}'`); let fields = fieldValues[fieldSource]; - if (!fields || fields === true || typeof fields === 'string') { + // if fields != string[] then we use the table columns as the fields + if (!fields || fields === true || typeof fields === 'string' || typeof fields[0] !== 'string') { fields = table.columns.map((c) => c.id); } diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 0ea1fd5084988..9e3c26a3e34ca 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,48 +1,56 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; exports[`discover Discover Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,currency,\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,geoip,manufacturer,\\"\\"\\"order_id\\"\\"\\",products,sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",591503,\\"[object Object], [object Object]\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",591709,\\"[object Object], [object Object]\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",590937,\\"[object Object], [object Object]\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",590976,\\"[object Object], [object Object]\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 770a6701db5a7..435f2faf021ba 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -1,91 +1,192 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Reporting APIs CSV Generation from SearchSource Settings set to fieldsFromSource Exports CSV with almost all selected fields when using fieldsFromSource 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,currency,\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,geoip,manufacturer,\\"\\"\\"order_id\\"\\"\\",products,sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",591503,\\"[object Object], [object Object]\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",591709,\\"[object Object], [object Object]\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",590937,\\"[object Object], [object Object]\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",590976,\\"[object Object], [object Object]\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" +exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fields when using defaults 1`] = ` +"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +" +`; + +exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with almost all fields when using fieldsFromSource 1`] = ` +"\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_source\\"\\"\\",\\"\\"\\"_type\\"\\"\\",category,\\"\\"\\"category.keyword\\"\\"\\",currency,\\"\\"\\"customer_birth_date\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",manufacturer,\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"products.base_price\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.unit_discount_amount\\"\\"\\",sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"-\\",EUR,\\"-\\",\\"Sultan Al\\",\\"-\\",\\"Sultan Al Boone\\",\\"-\\",MALE,19,Boone,\\"-\\",\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"-\\",EUR,\\"-\\",Pia,\\"-\\",\\"Pia Richards\\",\\"-\\",FEMALE,45,Richards,\\"-\\",\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Tigress Enterprises, Pyramidustries\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia " `; exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, UTC timezone 1`] = ` -"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" -\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" +"date,message +\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\" +\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\" " `; exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, custom timezone (New York) 1`] = ` -"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jan 1, 2015 @ 07:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" -\\"Jan 1, 2015 @ 07:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" +"date,message +\\"Jan 1, 2015 @ 07:10:30.123456789\\",\\"Hello 2\\" +\\"Jan 1, 2015 @ 07:10:30.000000000\\",\\"Hello 1\\" " `; exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, default to UTC 1`] = ` -"extension,\\"\\"\\"@timestamp\\"\\"\\",\\"\\"\\"utc_time\\"\\"\\",clientip,\\"\\"\\"relatedContent.article:modified_time\\"\\"\\",\\"\\"\\"relatedContent.article:published_time\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -jpg,\\"Sep 20, 2015 @ 10:26:48.725\\",\\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",\\"Jan 3, 2015 @ 16:26:58.000, Oct 28, 2014 @ 22:00:13.000, Nov 26, 2014 @ 01:19:52.000, Nov 26, 2014 @ 03:48:48.000, Nov 26, 2014 @ 02:36:20.000\\",\\"Mar 28, 2007 @ 00:03:55.000, Apr 11, 2008 @ 00:16:29.000, Feb 12, 2007 @ 20:02:30.000, Oct 19, 2005 @ 17:10:20.000, Jun 13, 2006 @ 21:06:38.000\\",\\"AU_x4AAaGFA8no6QjlMa\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 10:26:48.540\\",\\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",\\"Nov 26, 2014 @ 01:38:05.000, Nov 26, 2014 @ 01:40:12.000, Nov 27, 2014 @ 16:03:54.000, Nov 26, 2014 @ 01:17:50.000, Oct 28, 2014 @ 22:00:15.000\\",\\"Mar 22, 2006 @ 22:03:29.000, Apr 29, 2007 @ 20:04:15.000, Apr 14, 2008 @ 16:49:28.000, Oct 19, 2005 @ 17:10:56.000, Jun 5, 2008 @ 05:08:00.000\\",\\"AU_x3_g2GFA8no6QjjyV\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 10:26:48.353\\",\\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",\\"Nov 26, 2014 @ 04:41:33.000, Nov 27, 2014 @ 14:54:49.000\\",\\"May 11, 2006 @ 23:05:58.000, Mar 8, 2008 @ 14:00:00.000\\",\\"AU_x4AAZGFA8no6Qjk2z\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -png,\\"Sep 20, 2015 @ 10:26:45.468\\",\\"Sep 20, 2015 @ 10:26:45.468\\",\\"153.139.156.196\\",\\"Nov 27, 2014 @ 14:59:08.000, Nov 26, 2014 @ 02:18:38.000, Nov 27, 2014 @ 16:14:36.000, Nov 27, 2014 @ 00:15:19.000\\",\\"Sep 7, 2007 @ 00:40:28.000, Oct 17, 2005 @ 19:10:20.000, Dec 7, 2007 @ 15:00:42.000, Feb 5, 2008 @ 23:22:56.000\\",\\"AU_x4AAZGFA8no6Qjk5Y\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -css,\\"Sep 20, 2015 @ 10:26:34.063\\",\\"Sep 20, 2015 @ 10:26:34.063\\",\\"25.140.171.133\\",\\"Nov 27, 2014 @ 17:44:27.000, Nov 26, 2014 @ 02:55:44.000, Nov 27, 2014 @ 17:48:28.000, Nov 27, 2014 @ 18:43:09.000, Nov 26, 2014 @ 04:05:13.000\\",\\"Jul 12, 2007 @ 23:50:29.000, Jun 5, 2006 @ 20:06:32.000, Jun 9, 2008 @ 14:43:16.000, Dec 10, 2007 @ 15:47:00.000, Dec 18, 2007 @ 05:19:47.000\\",\\"AU_x3-TdGFA8no6QjiyL\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 10:26:11.181\\",\\"Sep 20, 2015 @ 10:26:11.181\\",\\"239.249.202.59\\",\\"Nov 26, 2014 @ 01:44:22.000, Apr 1, 2015 @ 16:01:40.000, Nov 27, 2014 @ 15:17:12.000, Nov 26, 2014 @ 01:24:00.000\\",\\"Feb 23, 2007 @ 01:02:07.000, Oct 19, 2007 @ 18:36:02.000, Aug 20, 2007 @ 02:33:32.000, Nov 13, 2006 @ 22:11:36.000\\",\\"AU_x3_BrGFA8no6QjjWt\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -css,\\"Sep 20, 2015 @ 10:26:00.639\\",\\"Sep 20, 2015 @ 10:26:00.639\\",\\"95.59.225.31\\",\\"Nov 26, 2014 @ 04:35:57.000\\",\\"Oct 23, 2005 @ 01:10:41.000\\",\\"AU_x3-TdGFA8no6Qji5N\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +"\\"\\"\\"@timestamp\\"\\"\\",clientip,extension +\\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg +\\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg +\\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg +\\"Sep 20, 2015 @ 10:26:45.468\\",\\"153.139.156.196\\",png +\\"Sep 20, 2015 @ 10:26:34.063\\",\\"25.140.171.133\\",css +\\"Sep 20, 2015 @ 10:26:11.181\\",\\"239.249.202.59\\",jpg +\\"Sep 20, 2015 @ 10:26:00.639\\",\\"95.59.225.31\\",css +\\"Sep 20, 2015 @ 10:26:00.094\\",\\"247.174.57.245\\",jpg +\\"Sep 20, 2015 @ 10:25:55.744\\",\\"116.126.47.226\\",css +\\"Sep 20, 2015 @ 10:25:54.701\\",\\"169.228.188.120\\",jpg +\\"Sep 20, 2015 @ 10:25:52.360\\",\\"74.224.77.232\\",css +\\"Sep 20, 2015 @ 10:25:49.913\\",\\"97.83.96.39\\",css +\\"Sep 20, 2015 @ 10:25:44.979\\",\\"175.188.44.145\\",css +\\"Sep 20, 2015 @ 10:25:40.968\\",\\"89.143.125.181\\",jpg +\\"Sep 20, 2015 @ 10:25:36.331\\",\\"231.169.195.137\\",css +\\"Sep 20, 2015 @ 10:25:34.064\\",\\"137.205.146.206\\",jpg +\\"Sep 20, 2015 @ 10:25:32.312\\",\\"53.0.188.251\\",jpg +\\"Sep 20, 2015 @ 10:25:27.254\\",\\"111.214.104.239\\",jpg +\\"Sep 20, 2015 @ 10:25:22.561\\",\\"111.46.85.146\\",jpg +\\"Sep 20, 2015 @ 10:25:06.674\\",\\"55.100.60.111\\",jpg +\\"Sep 20, 2015 @ 10:25:05.114\\",\\"34.197.178.155\\",jpg +\\"Sep 20, 2015 @ 10:24:55.114\\",\\"163.123.136.118\\",jpg +\\"Sep 20, 2015 @ 10:24:54.818\\",\\"11.195.163.57\\",jpg +\\"Sep 20, 2015 @ 10:24:53.742\\",\\"96.222.137.213\\",png +\\"Sep 20, 2015 @ 10:24:48.798\\",\\"227.228.214.218\\",jpg +\\"Sep 20, 2015 @ 10:24:20.223\\",\\"228.53.110.116\\",jpg +\\"Sep 20, 2015 @ 10:24:01.794\\",\\"196.131.253.111\\",png +\\"Sep 20, 2015 @ 10:23:49.521\\",\\"125.163.133.47\\",jpg +\\"Sep 20, 2015 @ 10:23:45.816\\",\\"148.47.216.255\\",jpg +\\"Sep 20, 2015 @ 10:23:36.052\\",\\"51.105.100.214\\",jpg +\\"Sep 20, 2015 @ 10:23:34.323\\",\\"41.210.252.157\\",gif +\\"Sep 20, 2015 @ 10:23:27.213\\",\\"248.163.75.193\\",png +\\"Sep 20, 2015 @ 10:23:14.866\\",\\"48.43.210.167\\",png +\\"Sep 20, 2015 @ 10:23:10.578\\",\\"33.95.78.209\\",css +\\"Sep 20, 2015 @ 10:23:07.001\\",\\"96.40.73.208\\",css +\\"Sep 20, 2015 @ 10:23:02.876\\",\\"174.32.230.63\\",jpg +\\"Sep 20, 2015 @ 10:23:00.019\\",\\"140.233.207.177\\",jpg +\\"Sep 20, 2015 @ 10:22:47.447\\",\\"37.127.124.65\\",jpg +\\"Sep 20, 2015 @ 10:22:45.803\\",\\"130.171.208.139\\",png +\\"Sep 20, 2015 @ 10:22:45.590\\",\\"39.250.210.253\\",jpg +\\"Sep 20, 2015 @ 10:22:43.997\\",\\"248.239.221.43\\",css +\\"Sep 20, 2015 @ 10:22:36.107\\",\\"232.64.207.109\\",gif +\\"Sep 20, 2015 @ 10:22:30.527\\",\\"24.186.122.118\\",jpg +\\"Sep 20, 2015 @ 10:22:25.697\\",\\"23.3.174.206\\",jpg +\\"Sep 20, 2015 @ 10:22:08.272\\",\\"185.170.80.142\\",php +\\"Sep 20, 2015 @ 10:21:40.822\\",\\"202.22.74.232\\",png +\\"Sep 20, 2015 @ 10:21:36.210\\",\\"39.227.27.167\\",jpg +\\"Sep 20, 2015 @ 10:21:19.154\\",\\"140.233.207.177\\",jpg +\\"Sep 20, 2015 @ 10:21:09.852\\",\\"22.151.97.227\\",jpg +\\"Sep 20, 2015 @ 10:21:06.079\\",\\"157.39.25.197\\",css +\\"Sep 20, 2015 @ 10:21:01.357\\",\\"37.127.124.65\\",jpg +\\"Sep 20, 2015 @ 10:20:56.519\\",\\"23.184.94.58\\",jpg +\\"Sep 20, 2015 @ 10:20:40.189\\",\\"80.83.92.252\\",jpg +\\"Sep 20, 2015 @ 10:20:27.012\\",\\"66.194.157.171\\",png +\\"Sep 20, 2015 @ 10:20:24.450\\",\\"15.191.218.38\\",jpg " `; exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, non-default timezone 1`] = ` -"extension,\\"\\"\\"@timestamp\\"\\"\\",\\"\\"\\"utc_time\\"\\"\\",clientip,\\"\\"\\"relatedContent.article:modified_time\\"\\"\\",\\"\\"\\"relatedContent.article:published_time\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -jpg,\\"Sep 20, 2015 @ 03:26:48.725\\",\\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",\\"Jan 3, 2015 @ 09:26:58.000, Oct 28, 2014 @ 15:00:13.000, Nov 25, 2014 @ 18:19:52.000, Nov 25, 2014 @ 20:48:48.000, Nov 25, 2014 @ 19:36:20.000\\",\\"Mar 27, 2007 @ 17:03:55.000, Apr 10, 2008 @ 17:16:29.000, Feb 12, 2007 @ 13:02:30.000, Oct 19, 2005 @ 10:10:20.000, Jun 13, 2006 @ 14:06:38.000\\",\\"AU_x4AAaGFA8no6QjlMa\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 03:26:48.540\\",\\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",\\"Nov 25, 2014 @ 18:38:05.000, Nov 25, 2014 @ 18:40:12.000, Nov 27, 2014 @ 09:03:54.000, Nov 25, 2014 @ 18:17:50.000, Oct 28, 2014 @ 15:00:15.000\\",\\"Mar 22, 2006 @ 15:03:29.000, Apr 29, 2007 @ 13:04:15.000, Apr 14, 2008 @ 09:49:28.000, Oct 19, 2005 @ 10:10:56.000, Jun 4, 2008 @ 22:08:00.000\\",\\"AU_x3_g2GFA8no6QjjyV\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 03:26:48.353\\",\\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",\\"Nov 25, 2014 @ 21:41:33.000, Nov 27, 2014 @ 07:54:49.000\\",\\"May 11, 2006 @ 16:05:58.000, Mar 8, 2008 @ 07:00:00.000\\",\\"AU_x4AAZGFA8no6Qjk2z\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -png,\\"Sep 20, 2015 @ 03:26:45.468\\",\\"Sep 20, 2015 @ 03:26:45.468\\",\\"153.139.156.196\\",\\"Nov 27, 2014 @ 07:59:08.000, Nov 25, 2014 @ 19:18:38.000, Nov 27, 2014 @ 09:14:36.000, Nov 26, 2014 @ 17:15:19.000\\",\\"Sep 6, 2007 @ 17:40:28.000, Oct 17, 2005 @ 12:10:20.000, Dec 7, 2007 @ 08:00:42.000, Feb 5, 2008 @ 16:22:56.000\\",\\"AU_x4AAZGFA8no6Qjk5Y\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -css,\\"Sep 20, 2015 @ 03:26:34.063\\",\\"Sep 20, 2015 @ 03:26:34.063\\",\\"25.140.171.133\\",\\"Nov 27, 2014 @ 10:44:27.000, Nov 25, 2014 @ 19:55:44.000, Nov 27, 2014 @ 10:48:28.000, Nov 27, 2014 @ 11:43:09.000, Nov 25, 2014 @ 21:05:13.000\\",\\"Jul 12, 2007 @ 16:50:29.000, Jun 5, 2006 @ 13:06:32.000, Jun 9, 2008 @ 07:43:16.000, Dec 10, 2007 @ 08:47:00.000, Dec 17, 2007 @ 22:19:47.000\\",\\"AU_x3-TdGFA8no6QjiyL\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -jpg,\\"Sep 20, 2015 @ 03:26:11.181\\",\\"Sep 20, 2015 @ 03:26:11.181\\",\\"239.249.202.59\\",\\"Nov 25, 2014 @ 18:44:22.000, Apr 1, 2015 @ 09:01:40.000, Nov 27, 2014 @ 08:17:12.000, Nov 25, 2014 @ 18:24:00.000\\",\\"Feb 22, 2007 @ 18:02:07.000, Oct 19, 2007 @ 11:36:02.000, Aug 19, 2007 @ 19:33:32.000, Nov 13, 2006 @ 15:11:36.000\\",\\"AU_x3_BrGFA8no6QjjWt\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" -css,\\"Sep 20, 2015 @ 03:26:00.639\\",\\"Sep 20, 2015 @ 03:26:00.639\\",\\"95.59.225.31\\",\\"Nov 25, 2014 @ 21:35:57.000\\",\\"Oct 22, 2005 @ 18:10:41.000\\",\\"AU_x3-TdGFA8no6Qji5N\\",\\"logstash-2015.09.20\\",\\"-\\",\\"-\\" +"\\"\\"\\"@timestamp\\"\\"\\",clientip,extension +\\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",jpg +\\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",jpg +\\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",jpg +\\"Sep 20, 2015 @ 03:26:45.468\\",\\"153.139.156.196\\",png +\\"Sep 20, 2015 @ 03:26:34.063\\",\\"25.140.171.133\\",css +\\"Sep 20, 2015 @ 03:26:11.181\\",\\"239.249.202.59\\",jpg +\\"Sep 20, 2015 @ 03:26:00.639\\",\\"95.59.225.31\\",css +\\"Sep 20, 2015 @ 03:26:00.094\\",\\"247.174.57.245\\",jpg +\\"Sep 20, 2015 @ 03:25:55.744\\",\\"116.126.47.226\\",css +\\"Sep 20, 2015 @ 03:25:54.701\\",\\"169.228.188.120\\",jpg +\\"Sep 20, 2015 @ 03:25:52.360\\",\\"74.224.77.232\\",css +\\"Sep 20, 2015 @ 03:25:49.913\\",\\"97.83.96.39\\",css +\\"Sep 20, 2015 @ 03:25:44.979\\",\\"175.188.44.145\\",css +\\"Sep 20, 2015 @ 03:25:40.968\\",\\"89.143.125.181\\",jpg +\\"Sep 20, 2015 @ 03:25:36.331\\",\\"231.169.195.137\\",css +\\"Sep 20, 2015 @ 03:25:34.064\\",\\"137.205.146.206\\",jpg +\\"Sep 20, 2015 @ 03:25:32.312\\",\\"53.0.188.251\\",jpg +\\"Sep 20, 2015 @ 03:25:27.254\\",\\"111.214.104.239\\",jpg +\\"Sep 20, 2015 @ 03:25:22.561\\",\\"111.46.85.146\\",jpg +\\"Sep 20, 2015 @ 03:25:06.674\\",\\"55.100.60.111\\",jpg +\\"Sep 20, 2015 @ 03:25:05.114\\",\\"34.197.178.155\\",jpg +\\"Sep 20, 2015 @ 03:24:55.114\\",\\"163.123.136.118\\",jpg +\\"Sep 20, 2015 @ 03:24:54.818\\",\\"11.195.163.57\\",jpg +\\"Sep 20, 2015 @ 03:24:53.742\\",\\"96.222.137.213\\",png +\\"Sep 20, 2015 @ 03:24:48.798\\",\\"227.228.214.218\\",jpg +\\"Sep 20, 2015 @ 03:24:20.223\\",\\"228.53.110.116\\",jpg +\\"Sep 20, 2015 @ 03:24:01.794\\",\\"196.131.253.111\\",png +\\"Sep 20, 2015 @ 03:23:49.521\\",\\"125.163.133.47\\",jpg +\\"Sep 20, 2015 @ 03:23:45.816\\",\\"148.47.216.255\\",jpg +\\"Sep 20, 2015 @ 03:23:36.052\\",\\"51.105.100.214\\",jpg +\\"Sep 20, 2015 @ 03:23:34.323\\",\\"41.210.252.157\\",gif +\\"Sep 20, 2015 @ 03:23:27.213\\",\\"248.163.75.193\\",png +\\"Sep 20, 2015 @ 03:23:14.866\\",\\"48.43.210.167\\",png +\\"Sep 20, 2015 @ 03:23:10.578\\",\\"33.95.78.209\\",css +\\"Sep 20, 2015 @ 03:23:07.001\\",\\"96.40.73.208\\",css +\\"Sep 20, 2015 @ 03:23:02.876\\",\\"174.32.230.63\\",jpg +\\"Sep 20, 2015 @ 03:23:00.019\\",\\"140.233.207.177\\",jpg +\\"Sep 20, 2015 @ 03:22:47.447\\",\\"37.127.124.65\\",jpg +\\"Sep 20, 2015 @ 03:22:45.803\\",\\"130.171.208.139\\",png +\\"Sep 20, 2015 @ 03:22:45.590\\",\\"39.250.210.253\\",jpg +\\"Sep 20, 2015 @ 03:22:43.997\\",\\"248.239.221.43\\",css +\\"Sep 20, 2015 @ 03:22:36.107\\",\\"232.64.207.109\\",gif +\\"Sep 20, 2015 @ 03:22:30.527\\",\\"24.186.122.118\\",jpg +\\"Sep 20, 2015 @ 03:22:25.697\\",\\"23.3.174.206\\",jpg +\\"Sep 20, 2015 @ 03:22:08.272\\",\\"185.170.80.142\\",php +\\"Sep 20, 2015 @ 03:21:40.822\\",\\"202.22.74.232\\",png +\\"Sep 20, 2015 @ 03:21:36.210\\",\\"39.227.27.167\\",jpg +\\"Sep 20, 2015 @ 03:21:19.154\\",\\"140.233.207.177\\",jpg +\\"Sep 20, 2015 @ 03:21:09.852\\",\\"22.151.97.227\\",jpg +\\"Sep 20, 2015 @ 03:21:06.079\\",\\"157.39.25.197\\",css +\\"Sep 20, 2015 @ 03:21:01.357\\",\\"37.127.124.65\\",jpg +\\"Sep 20, 2015 @ 03:20:56.519\\",\\"23.184.94.58\\",jpg +\\"Sep 20, 2015 @ 03:20:40.189\\",\\"80.83.92.252\\",jpg +\\"Sep 20, 2015 @ 03:20:27.012\\",\\"66.194.157.171\\",png +\\"Sep 20, 2015 @ 03:20:24.450\\",\\"15.191.218.38\\",jpg " `; exports[`Reporting APIs CSV Generation from SearchSource non-timebased Handle _id and _index columns 1`] = ` -"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos,\\"-\\",\\"-\\" -\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos,\\"-\\",\\"-\\" +"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\" +\\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos +\\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos " `; exports[`Reporting APIs CSV Generation from SearchSource non-timebased With filters and non-timebased data 1`] = ` -"name,\\"\\"\\"@date\\"\\"\\",power,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jonelle-Jane Marth\\",\\"Feb 11, 2019 @ 03:21:31.000\\",1,UuEOUGkBxhhfVX4mK8ae,sales,\\"-\\",\\"-\\" -\\"Suzie-May Rishel\\",\\"Dec 4, 2018 @ 16:51:31.000\\",1,WOEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Suzie-May Rishel\\",\\"Jan 7, 2019 @ 22:06:31.000\\",2,VeEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Rosana Casto\\",\\"Apr 20, 2018 @ 13:51:31.000\\",2,bOEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Stephen Cortez\\",\\"Aug 1, 2018 @ 05:36:31.000\\",4,\\"Y-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" -\\"Jonelle-Jane Marth\\",\\"Mar 28, 2018 @ 18:21:31.000\\",6,buEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Jonelle-Jane Marth\\",\\"Sep 27, 2018 @ 06:21:31.000\\",7,XuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Florinda Alejandro\\",\\"Aug 12, 2018 @ 15:21:31.000\\",10,YuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Jonelle-Jane Marth\\",\\"Jun 16, 2018 @ 14:36:31.000\\",14,\\"Z-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" -\\"Suzie-May Rishel\\",\\"Mar 17, 2018 @ 08:36:31.000\\",19,\\"b-EOUGkBxhhfVX4mK8af\\",sales,\\"-\\",\\"-\\" -\\"Suzie-May Rishel\\",\\"Jun 28, 2018 @ 00:21:31.000\\",20,ZuEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" -\\"Florinda Alejandro\\",\\"May 13, 2018 @ 09:21:31.000\\",22,auEOUGkBxhhfVX4mK8af,sales,\\"-\\",\\"-\\" +"name,power +\\"Jonelle-Jane Marth\\",1 +\\"Suzie-May Rishel\\",1 +\\"Suzie-May Rishel\\",2 +\\"Rosana Casto\\",2 +\\"Stephen Cortez\\",4 +\\"Jonelle-Jane Marth\\",6 +\\"Jonelle-Jane Marth\\",7 +\\"Florinda Alejandro\\",10 +\\"Jonelle-Jane Marth\\",14 +\\"Suzie-May Rishel\\",19 +\\"Suzie-May Rishel\\",20 +\\"Florinda Alejandro\\",22 " `; exports[`Reporting APIs CSV Generation from SearchSource validation Searches large amount of data, stops at Max Size Reached 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",currency,category,\\"\\"\\"customer_id\\"\\"\\",sku,\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",716724,3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Shoes, Women's Clothing\\",45,\\"ZO0006400064, ZO0150601506\\",591503,9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",12,\\"ZO0638206382, ZO0038800388\\",591709,BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",52,\\"ZO0297602976, ZO0565605656\\",590937,KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",29,\\"ZO0561405614, ZO0281602816\\",590976,KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes, Men's Clothing\\",41,\\"ZO0385003850, ZO0408604086\\",591636,awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Shoes\\",30,\\"ZO0505605056, ZO0513605136\\",591539,eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",41,\\"ZO0276702767, ZO0291702917\\",591598,egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing\\",44,\\"ZO0046600466, ZO0050800508\\",590927,fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing, Men's Shoes\\",48,\\"ZO0455604556, ZO0680806808\\",590970,gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Women's Clothing, Women's Shoes\\",46,\\"ZO0229002290, ZO0674406744\\",591299,6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",36,\\"ZO0529905299, ZO0617006170\\",591133,6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",5,EUR,\\"Men's Clothing\\",13,\\"ZO0299402994, ZO0433504335\\",591175,6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\" +"\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts index 7cd09f2d8a293..2b0d01b6f5f5e 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts @@ -43,113 +43,158 @@ export default function ({ getService }: FtrProviderContext) { await reportingAPI.deleteAllReports(); }); - describe('Settings set to fieldsFromSource', () => { - it('Exports CSV with almost all selected fields when using fieldsFromSource', async () => { - await esArchiver.load('reporting/ecommerce'); - await esArchiver.load('reporting/ecommerce_kibana'); - - const { - status: resStatus, - text: resText, - type: resType, - } = (await generateAPI.getCSVFromSearchSource( - getMockJobParams({ - searchSource: { - query: { query: '', language: 'kuery' }, - index: '5193f870-d861-11e9-a311-0fa548c5f953', - sort: [{ order_date: 'desc' }], - fieldsFromSource: [ - '_id', - '_index', - '_score', - '_source', - '_type', - 'category', - 'category.keyword', - 'currency', - 'customer_birth_date', - 'customer_first_name', - 'customer_first_name.keyword', - 'customer_full_name', - 'customer_full_name.keyword', - 'customer_gender', - 'customer_id', - 'customer_last_name', - 'customer_last_name.keyword', - 'customer_phone', - 'day_of_week', - 'day_of_week_i', - 'email', - 'geoip.city_name', - 'geoip.continent_name', - 'geoip.country_iso_code', - 'geoip.location', - 'geoip.region_name', - 'manufacturer', - 'manufacturer.keyword', - 'order_date', - 'order_id', - 'products._id', - 'products._id.keyword', - 'products.base_price', - 'products.base_unit_price', - 'products.category', - 'products.category.keyword', - 'products.created_on', - 'products.discount_amount', - 'products.discount_percentage', - 'products.manufacturer', - 'products.manufacturer.keyword', - 'products.min_price', - 'products.price', - 'products.product_id', - 'products.product_name', - 'products.product_name.keyword', - 'products.quantity', - 'products.sku', - 'products.tax_amount', - 'products.taxful_price', - 'products.taxless_price', - 'products.unit_discount_amount', - 'sku', - 'taxful_total_price', - 'taxless_total_price', - 'total_quantity', - 'total_unique_products', - 'type', - 'user', - ], + it('Exports CSV with almost all fields when using fieldsFromSource', async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + + const { + status: resStatus, + text: resText, + type: resType, + } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], + fieldsFromSource: [ + '_id', + '_index', + '_score', + '_source', + '_type', + 'category', + 'category.keyword', + 'currency', + 'customer_birth_date', + 'customer_first_name', + 'customer_first_name.keyword', + 'customer_full_name', + 'customer_full_name.keyword', + 'customer_gender', + 'customer_id', + 'customer_last_name', + 'customer_last_name.keyword', + 'customer_phone', + 'day_of_week', + 'day_of_week_i', + 'email', + 'geoip.city_name', + 'geoip.continent_name', + 'geoip.country_iso_code', + 'geoip.location', + 'geoip.region_name', + 'manufacturer', + 'manufacturer.keyword', + 'order_date', + 'order_id', + 'products._id', + 'products._id.keyword', + 'products.base_price', + 'products.base_unit_price', + 'products.category', + 'products.category.keyword', + 'products.created_on', + 'products.discount_amount', + 'products.discount_percentage', + 'products.manufacturer', + 'products.manufacturer.keyword', + 'products.min_price', + 'products.price', + 'products.product_id', + 'products.product_name', + 'products.product_name.keyword', + 'products.quantity', + 'products.sku', + 'products.tax_amount', + 'products.taxful_price', + 'products.taxless_price', + 'products.unit_discount_amount', + 'sku', + 'taxful_total_price', + 'taxless_total_price', + 'total_quantity', + 'total_unique_products', + 'type', + 'user', + ], + filter: [], + parent: { + query: { language: 'kuery', query: '' }, filter: [], parent: { - query: { language: 'kuery', query: '' }, - filter: [], - parent: { - filter: [ - { - meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, - range: { - order_date: { - gte: '2019-03-23T03:06:17.785Z', - lte: '2019-10-04T02:33:16.708Z', - format: 'strict_date_optional_time', - }, + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: '2019-03-23T03:06:17.785Z', + lte: '2019-10-04T02:33:16.708Z', + format: 'strict_date_optional_time', }, }, - ], - }, + }, + ], }, }, - browserTimezone: 'UTC', - title: 'testfooyu78yt90-', - }) - )) as supertest.Response; - expect(resStatus).to.eql(200); - expect(resType).to.eql('text/csv'); - expectSnapshot(resText).toMatch(); + }, + browserTimezone: 'UTC', + title: 'testfooyu78yt90-', + }) + )) as supertest.Response; + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); - await esArchiver.unload('reporting/ecommerce'); - await esArchiver.unload('reporting/ecommerce_kibana'); - }); + it('Exports CSV with all fields when using defaults', async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + + const { + status: resStatus, + text: resText, + type: resType, + } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], + fields: ['*'], + filter: [], + parent: { + query: { language: 'kuery', query: '' }, + filter: [], + parent: { + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: '2019-03-23T03:06:17.785Z', + lte: '2019-10-04T02:33:16.708Z', + format: 'strict_date_optional_time', + }, + }, + }, + ], + }, + }, + }, + browserTimezone: 'UTC', + title: 'testfooyu78yt90-', + }) + )) as supertest.Response; + expect(resStatus).to.eql(200); + expect(resType).to.eql('text/csv'); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); }); describe('date formatting', () => { From c25ef8e4e64c9a60ebf2fc4a295327047cf5dac7 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 12 Mar 2021 11:16:44 -0700 Subject: [PATCH 36/51] fix double-escaping --- .../generate_csv/generate_csv.ts | 18 +++++++------- .../discover/__snapshots__/reporting.snap | 24 +++++++++++++++---- .../csv_searchsource_immediate.snap | 20 +++++++++++----- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index fead01caa2959..c1b8adee972d0 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -110,7 +110,7 @@ export class CsvGenerator { return this._formatters; } - private checkForFormulas(settings: CsvExportSettings) { + private escapeValues(settings: CsvExportSettings) { return (value: string) => { if (settings.checkForFormulas && cellHasFormulas(value)) { this.csvContainsFormulas = true; // set warning if cell value has a formula @@ -131,7 +131,13 @@ export class CsvGenerator { let fields = fieldValues[fieldSource]; // if fields != string[] then we use the table columns as the fields - if (!fields || fields === true || typeof fields === 'string' || typeof fields[0] !== 'string') { + if ( + !fields || + fields === true || + typeof fields === 'string' || + typeof fields[0] !== 'string' || + fields[0] === '*' + ) { fields = table.columns.map((c) => c.id); } @@ -180,11 +186,7 @@ export class CsvGenerator { settings: CsvExportSettings ) { this.logger.debug(`Building CSV header row...`); - const header = - fields - .map(settings.escapeValue) - .map(this.checkForFormulas(settings)) - .join(settings.separator) + '\n'; + const header = fields.map(this.escapeValues(settings)).join(settings.separator) + '\n'; if (!builder.tryAppend(header)) { return { @@ -216,7 +218,7 @@ export class CsvGenerator { fields .map((f) => ({ column: f, data: dataTableRow[f] })) .map(this.formatCellValues(formatters)) - .map(this.checkForFormulas(settings)) + .map(this.escapeValues(settings)) .join(settings.separator) + '\n'; if (!builder.tryAppend(row)) { diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 9e3c26a3e34ca..0100f6d827241 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" @@ -19,7 +19,7 @@ exports[`discover Discover Generate CSV: archived search generates a report with `; exports[`discover Discover Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" @@ -37,7 +37,7 @@ exports[`discover Discover Generate CSV: archived search generates a report with `; exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" @@ -55,11 +55,25 @@ exports[`discover Discover Generate CSV: archived search generates a report with `; exports[`discover Discover Generate CSV: new search generates a report from a new search with data: default 1`] = ` -"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" +\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" " `; exports[`discover Discover Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` -"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" +\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" " `; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 435f2faf021ba..86fec54d8c4d5 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -1,14 +1,22 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fields when using defaults 1`] = ` -"\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",type,\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",sku,\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"category.keyword\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",manufacturer,\\"\\"\\"products.unit_discount_amount\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",currency,\\"\\"\\"products.base_price\\"\\"\\",email,\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",category,\\"\\"\\"customer_id\\"\\"\\",user,\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_type\\"\\"\\" +"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" +\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" " `; exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with almost all fields when using fieldsFromSource 1`] = ` -"\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\",\\"\\"\\"_score\\"\\"\\",\\"\\"\\"_source\\"\\"\\",\\"\\"\\"_type\\"\\"\\",category,\\"\\"\\"category.keyword\\"\\"\\",currency,\\"\\"\\"customer_birth_date\\"\\"\\",\\"\\"\\"customer_first_name\\"\\"\\",\\"\\"\\"customer_first_name.keyword\\"\\"\\",\\"\\"\\"customer_full_name\\"\\"\\",\\"\\"\\"customer_full_name.keyword\\"\\"\\",\\"\\"\\"customer_gender\\"\\"\\",\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"customer_last_name\\"\\"\\",\\"\\"\\"customer_last_name.keyword\\"\\"\\",\\"\\"\\"customer_phone\\"\\"\\",\\"\\"\\"day_of_week\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",email,\\"\\"\\"geoip.city_name\\"\\"\\",\\"\\"\\"geoip.continent_name\\"\\"\\",\\"\\"\\"geoip.country_iso_code\\"\\"\\",\\"\\"\\"geoip.location\\"\\"\\",\\"\\"\\"geoip.region_name\\"\\"\\",manufacturer,\\"\\"\\"manufacturer.keyword\\"\\"\\",\\"\\"\\"order_date\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"products._id\\"\\"\\",\\"\\"\\"products._id.keyword\\"\\"\\",\\"\\"\\"products.base_price\\"\\"\\",\\"\\"\\"products.base_unit_price\\"\\"\\",\\"\\"\\"products.category\\"\\"\\",\\"\\"\\"products.category.keyword\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",\\"\\"\\"products.discount_amount\\"\\"\\",\\"\\"\\"products.discount_percentage\\"\\"\\",\\"\\"\\"products.manufacturer\\"\\"\\",\\"\\"\\"products.manufacturer.keyword\\"\\"\\",\\"\\"\\"products.min_price\\"\\"\\",\\"\\"\\"products.price\\"\\"\\",\\"\\"\\"products.product_id\\"\\"\\",\\"\\"\\"products.product_name\\"\\"\\",\\"\\"\\"products.product_name.keyword\\"\\"\\",\\"\\"\\"products.quantity\\"\\"\\",\\"\\"\\"products.sku\\"\\"\\",\\"\\"\\"products.tax_amount\\"\\"\\",\\"\\"\\"products.taxful_price\\"\\"\\",\\"\\"\\"products.taxless_price\\"\\"\\",\\"\\"\\"products.unit_discount_amount\\"\\"\\",sku,\\"\\"\\"taxful_total_price\\"\\"\\",\\"\\"\\"taxless_total_price\\"\\"\\",\\"\\"\\"total_quantity\\"\\"\\",\\"\\"\\"total_unique_products\\"\\"\\",type,user +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_source\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_birth_date\\",\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user 3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"-\\",EUR,\\"-\\",\\"Sultan Al\\",\\"-\\",\\"Sultan Al Boone\\",\\"-\\",MALE,19,Boone,\\"-\\",\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan 9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"-\\",EUR,\\"-\\",Pia,\\"-\\",\\"Pia Richards\\",\\"-\\",FEMALE,45,Richards,\\"-\\",\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Tigress Enterprises, Pyramidustries\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"-\\",EUR,\\"-\\",Brigitte,\\"-\\",\\"Brigitte Meyer\\",\\"-\\",FEMALE,12,Meyer,\\"-\\",\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Spherecords, Tigress Enterprises\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte " `; @@ -27,7 +35,7 @@ exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatt `; exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, default to UTC 1`] = ` -"\\"\\"\\"@timestamp\\"\\"\\",clientip,extension +"\\"@timestamp\\",clientip,extension \\"Sep 20, 2015 @ 10:26:48.725\\",\\"74.214.76.90\\",jpg \\"Sep 20, 2015 @ 10:26:48.540\\",\\"146.86.123.109\\",jpg \\"Sep 20, 2015 @ 10:26:48.353\\",\\"233.126.159.144\\",jpg @@ -87,7 +95,7 @@ exports[`Reporting APIs CSV Generation from SearchSource date formatting With fi `; exports[`Reporting APIs CSV Generation from SearchSource date formatting With filters and timebased data, non-default timezone 1`] = ` -"\\"\\"\\"@timestamp\\"\\"\\",clientip,extension +"\\"@timestamp\\",clientip,extension \\"Sep 20, 2015 @ 03:26:48.725\\",\\"74.214.76.90\\",jpg \\"Sep 20, 2015 @ 03:26:48.540\\",\\"146.86.123.109\\",jpg \\"Sep 20, 2015 @ 03:26:48.353\\",\\"233.126.159.144\\",jpg @@ -147,7 +155,7 @@ exports[`Reporting APIs CSV Generation from SearchSource date formatting With fi `; exports[`Reporting APIs CSV Generation from SearchSource non-timebased Handle _id and _index columns 1`] = ` -"date,message,\\"\\"\\"_id\\"\\"\\",\\"\\"\\"_index\\"\\"\\" +"date,message,\\"_id\\",\\"_index\\" \\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\",2,nanos \\"Jan 1, 2015 @ 12:10:30.000000000\\",\\"Hello 1\\",1,nanos " @@ -171,7 +179,7 @@ exports[`Reporting APIs CSV Generation from SearchSource non-timebased With filt `; exports[`Reporting APIs CSV Generation from SearchSource validation Searches large amount of data, stops at Max Size Reached 1`] = ` -"\\"\\"\\"order_date\\"\\"\\",category,currency,\\"\\"\\"customer_id\\"\\"\\",\\"\\"\\"order_id\\"\\"\\",\\"\\"\\"day_of_week_i\\"\\"\\",\\"\\"\\"products.created_on\\"\\"\\",sku +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" From fc0e22221dcb70b01f3d3826efe9d1ae25a24b18 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 12 Mar 2021 16:57:12 -0700 Subject: [PATCH 37/51] fix test snapshots and refactoring --- .../search/es_search/es_search_strategy.ts | 3 -- .../helpers/get_sharing_data.test.ts | 3 -- .../server/search/es_search_strategy.ts | 3 -- .../reporting/__snapshots__/download_csv.snap | 28 +++++++++---------- .../functional/apps/discover/reporting.ts | 26 +++++++++-------- 5 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index f0ae60139334c..cc81dce94c4ec 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -49,9 +49,6 @@ export const esSearchStrategyProvider = ( const response = shimHitsTotal(body, options); return toKibanaSearchResponse(response); } catch (e) { - if (e.body.error) { - logger.error(e.body.error); - } throw getKbnServerError(e); } }; diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts index d3a23fa6a939a..925576cee1596 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts @@ -27,9 +27,6 @@ describe('getSharingData', () => { expect(result).toMatchInlineSnapshot(` Object { "searchSource": Object { - "fields": Array [ - "*", - ], "index": "the-index-pattern-id", "sort": Array [ Object { diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts index 4c02ef0d49bd0..fc1cc63146358 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts @@ -84,9 +84,6 @@ export const enhancedEsSearchStrategyProvider = ( tap((response) => (id = response.id)), tap(searchUsageObserver(logger, usage)), catchError((e) => { - if (e.body.error) { - logger.error(e.body.error); - } throw getKbnServerError(e); }) ); diff --git a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap index 5df05de3b9fd9..0852989cd6e9e 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap +++ b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap @@ -1,20 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a CSV export of a saved search panel 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 73258d712557a..b9ab4bc2b57f2 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -38,6 +38,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('Check Available', () => { + beforeEach(() => PageObjects.common.navigateToApp('discover')); + it('is not available if new', async () => { await PageObjects.reporting.openCsvReportingPanel(); expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true'); @@ -128,18 +130,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('Generate CSV: archived search', () => { - before(async () => { - await esArchiver.load('reporting/ecommerce'); - await esArchiver.load('reporting/ecommerce_kibana'); - }); - - after(async () => { - await esArchiver.unload('reporting/ecommerce'); - await esArchiver.unload('reporting/ecommerce_kibana'); - }); - - beforeEach(() => PageObjects.common.navigateToApp('discover')); - const setupPage = async () => { const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; const toTime = 'Aug 23, 2019 @ 16:18:51.821'; @@ -158,6 +148,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return res; }; + before(async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + }); + + after(async () => { + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); + + beforeEach(() => PageObjects.common.navigateToApp('discover')); + it('generates a report with data', async () => { await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); From 6640e2467894cdfa5c2d405604e64749659dfd79 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sat, 13 Mar 2021 14:06:01 -0700 Subject: [PATCH 38/51] fix other tests --- .../reporting/__snapshots__/download_csv.snap | 32 +++++++++---------- .../apps/dashboard/reporting/download_csv.ts | 4 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap index 0852989cd6e9e..29ba0ab5b2be0 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap +++ b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a CSV export of a saved search panel 1`] = ` +exports[`dashboard Reporting Download CSV E-Commerce Data Download CSV export of a saved search panel 1`] = ` "\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" @@ -19,24 +19,24 @@ exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a CSV export `; exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a filtered CSV export of a saved search panel 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"order_date\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" " `; -exports[`dashboard Reporting Download CSV Field Formatters and Scripted Fields Downloads a CSV export of a saved search panel 1`] = ` +exports[`dashboard Reporting Download CSV Field Formatters and Scripted Fields Download CSV export of a saved search panel 1`] = ` "date,\\"_id\\",name,gender,value,year,\\"years_ago\\",\\"date_informal\\" \\"Jan 1, 1984 @ 00:00:00.000\\",\\"1984-Fethany-F\\",Fethany,F,5,1984,\\"35.00000000000000000000\\",\\"Jan 1st 84\\" \\"Jan 1, 1983 @ 00:00:00.000\\",\\"1983-Fethany-F\\",Fethany,F,\\"1,043\\",1983,\\"36.00000000000000000000\\",\\"Jan 1st 83\\" diff --git a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts index 126e0a7006403..d4a909f6a0474 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts +++ b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts @@ -74,7 +74,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload('reporting/ecommerce_kibana'); }); - it('Downloads a CSV export of a saved search panel', async function () { + it('Download CSV export of a saved search panel', async function () { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); await clickActionsMenu('EcommerceData'); @@ -122,7 +122,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload('reporting/hugedata'); }); - it('Downloads a CSV export of a saved search panel', async () => { + it('Download CSV export of a saved search panel', async () => { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.loadSavedDashboard('names dashboard'); await PageObjects.timePicker.setAbsoluteRange( From 9b374868db72e42fab9139801c21d4b4e4fc606a Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sat, 13 Mar 2021 14:13:36 -0700 Subject: [PATCH 39/51] fix test --- .../apps/discover/__snapshots__/reporting.snap | 10 +++++----- x-pack/test/functional/apps/discover/reporting.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 0100f6d827241..cfe7b1d2e30c5 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`discover Discover Generate CSV: archived search generates a report with data 1`] = ` +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with data 1`] = ` "\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" @@ -18,7 +18,7 @@ exports[`discover Discover Generate CSV: archived search generates a report with " `; -exports[`discover Discover Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` "\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" @@ -36,7 +36,7 @@ exports[`discover Discover Generate CSV: archived search generates a report with " `; -exports[`discover Discover Generate CSV: archived search generates a report with filtered data 1`] = ` +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with filtered data 1`] = ` "\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" @@ -54,7 +54,7 @@ exports[`discover Discover Generate CSV: archived search generates a report with " `; -exports[`discover Discover Generate CSV: new search generates a report from a new search with data: default 1`] = ` +exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` "\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" \\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ \\"\\"coordinates\\"\\": [ @@ -66,7 +66,7 @@ exports[`discover Discover Generate CSV: new search generates a report from a ne " `; -exports[`discover Discover Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` +exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` "\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" \\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ \\"\\"coordinates\\"\\": [ diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index b9ab4bc2b57f2..52b5060e9dbe0 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -21,10 +21,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue }); }; - describe('Discover', () => { + describe('Discover CSV Export', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); - await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); await browser.setWindowSize(1600, 850); }); after('clean up archives', async () => { From 73487e16957d0626823fc997e65c65c6a65feba2 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Sun, 14 Mar 2021 12:37:05 -0700 Subject: [PATCH 40/51] fix default index pattern in functional tests --- x-pack/test/functional/apps/discover/reporting.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 52b5060e9dbe0..d7dd961e2f103 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -24,6 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Discover CSV Export', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); + await esArchiver.load('reporting/ecommerce'); await esArchiver.load('reporting/ecommerce_kibana'); await browser.setWindowSize(1600, 850); }); From 2ecac7fdd92776e9435bd6f0b11e92bd74c70d8e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 10:16:11 -0700 Subject: [PATCH 41/51] fix ts and sort fields when they come from API response --- .../generate_csv/generate_csv.ts | 39 ++++++++++++------- .../discover/__snapshots__/reporting.snap | 12 +++--- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index c1b8adee972d0..eb1bd778dd7e9 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -43,6 +43,21 @@ interface Dependencies { fieldFormatsRegistry: IFieldFormatsRegistry; } +// Function to check if the field name values can be used as the header row +function isPlainStringArray( + fields: SearchFieldValue[] | string | boolean | undefined +): fields is string[] { + let result = true; + if (Array.isArray(fields)) { + fields.forEach((field) => { + if (typeof field !== 'string') { + result = false; + } + }); + } + return result; +} + export class CsvGenerator { private _formatters: Record | null = null; private csvContainsFormulas = false; @@ -127,21 +142,19 @@ export class CsvGenerator { fieldsFromSource: searchSource.getField('fieldsFromSource'), }; const fieldSource = fieldValues.fieldsFromSource ? 'fieldsFromSource' : 'fields'; - this.logger.info(`Getting search source fields from: '${fieldSource}'`); - - let fields = fieldValues[fieldSource]; - // if fields != string[] then we use the table columns as the fields - if ( - !fields || - fields === true || - typeof fields === 'string' || - typeof fields[0] !== 'string' || - fields[0] === '*' - ) { - fields = table.columns.map((c) => c.id); + this.logger.debug(`Getting search source fields from: '${fieldSource}'`); + + const fields = fieldValues[fieldSource]; + // Check if field name values are string[] and if the fields are user-defined + if (isPlainStringArray(fields)) { + return fields; } - return fields as string[]; // FIXME: fix TS + // Default to using the table column IDs as the fields + const columnIds = table.columns.map((c) => c.id); + // Fields in the API response don't come sorted - they need to be sorted client-side + columnIds.sort(); + return columnIds; } private formatCellValues(formatters: Record) { diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index cfe7b1d2e30c5..15dd3256607d2 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -55,25 +55,25 @@ exports[`discover Discover CSV Export Generate CSV: archived search generates a `; exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` -"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" -\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,,Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ \\"\\"coordinates\\"\\": [ 54.4, 24.5 ], \\"\\"type\\"\\": \\"\\"Point\\"\\" -}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan " `; exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` -"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" -\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,,Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ \\"\\"coordinates\\"\\": [ 54.4, 24.5 ], \\"\\"type\\"\\": \\"\\"Point\\"\\" -}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan " `; From 81d54bf8ccd23639d55391b7cb5d976af9c5b9a2 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 10:33:49 -0700 Subject: [PATCH 42/51] --wip-- [skip ci] --- .../generate_csv/generate_csv.ts | 2 +- .../csv_searchsource_immediate.snap | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index eb1bd778dd7e9..8a34d87972d05 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -50,7 +50,7 @@ function isPlainStringArray( let result = true; if (Array.isArray(fields)) { fields.forEach((field) => { - if (typeof field !== 'string') { + if (typeof field !== 'string' || field === '*' || field === '_source') { result = false; } }); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 86fec54d8c4d5..5013aa1b01e49 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -1,22 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fields when using defaults 1`] = ` -"\\"products.manufacturer\\",\\"products.discount_amount\\",\\"products.base_unit_price\\",type,\\"products.discount_percentage\\",\\"products._id.keyword\\",\\"day_of_week_i\\",\\"total_quantity\\",\\"taxless_total_price\\",\\"total_unique_products\\",\\"geoip.continent_name\\",sku,\\"customer_full_name.keyword\\",\\"category.keyword\\",\\"products.taxless_price\\",\\"products.quantity\\",\\"products.price\\",\\"customer_first_name\\",\\"customer_phone\\",\\"geoip.region_name\\",\\"customer_full_name\\",\\"geoip.country_iso_code\\",\\"order_id\\",\\"products._id\\",\\"products.product_name.keyword\\",\\"products.product_id\\",\\"products.category\\",\\"products.manufacturer.keyword\\",manufacturer,\\"products.unit_discount_amount\\",\\"customer_last_name\\",\\"geoip.location\\",\\"products.tax_amount\\",\\"products.product_name\\",\\"products.min_price\\",\\"manufacturer.keyword\\",\\"products.taxful_price\\",currency,\\"products.base_price\\",email,\\"day_of_week\\",\\"products.sku\\",\\"customer_last_name.keyword\\",\\"products.category.keyword\\",\\"geoip.city_name\\",\\"customer_first_name.keyword\\",\\"order_date\\",\\"products.created_on\\",category,\\"customer_id\\",user,\\"customer_gender\\",\\"taxful_total_price\\",\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\" -\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",order,\\"0, 0, 0, 0\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",5,4,\\"173.96\\",4,Asia,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"Sultan Al Boone\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"1, 1, 1, 1\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Sultan Al\\",,\\"Abu Dhabi\\",\\"Sultan Al Boone\\",AE,716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"0, 0, 0, 0\\",Boone,\\"{ +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,,Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ \\"\\"coordinates\\"\\": [ 54.4, 24.5 ], \\"\\"type\\"\\": \\"\\"Point\\"\\" -}\\",\\"0, 0, 0, 0\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"79.99, 59.99, 21.99, 11.99\\",EUR,\\"79.99, 59.99, 21.99, 11.99\\",\\"sultan al@boone-family.zzz\\",Saturday,\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",Boone,\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Abu Dhabi\\",\\"Sultan Al\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",19,sultan,MALE,\\"173.96\\",3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan " `; exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with almost all fields when using fieldsFromSource 1`] = ` -"\\"_id\\",\\"_index\\",\\"_score\\",\\"_source\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_birth_date\\",\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"-\\",EUR,\\"-\\",\\"Sultan Al\\",\\"-\\",\\"Sultan Al Boone\\",\\"-\\",MALE,19,Boone,\\"-\\",\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan -9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"-\\",EUR,\\"-\\",Pia,\\"-\\",\\"Pia Richards\\",\\"-\\",FEMALE,45,Richards,\\"-\\",\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Tigress Enterprises, Pyramidustries\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia -BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"-\\",EUR,\\"-\\",Brigitte,\\"-\\",\\"Brigitte Meyer\\",\\"-\\",FEMALE,12,Meyer,\\"-\\",\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Spherecords, Tigress Enterprises\\",\\"-\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"-\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,currency,\\"customer_first_name\\",\\"customer_full_name\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,geoip,manufacturer,\\"order_date\\",\\"order_id\\",products,\\"products.created_on\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte +KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd +KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590976,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert +awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,\\"Jim Hansen\\",MALE,41,Hansen,\\"-\\",Saturday,5,\\"jim@hansen-family.zzz\\",[object Object],\\"Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591636,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\",99.98,99.98,2,2,order,jim " `; From f183650afa2e970249f6c1b49b3ce6ceb3d280a4 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 11:09:49 -0700 Subject: [PATCH 43/51] fix formatting and increase maxSizeBytes for testing --- .../generate_csv/generate_csv.ts | 21 +++++-- .../reporting_and_security.config.ts | 2 +- .../csv_searchsource_immediate.snap | 57 +++++++++++++++++-- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 8a34d87972d05..4df6c70fc0239 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -158,9 +158,15 @@ export class CsvGenerator { } private formatCellValues(formatters: Record) { - return ({ column: tableColumn, data: dataTableCell }: { column: string; data: any }) => { - let cell: string[] | string; - // guard against _score, _type, etc + return ({ + column: tableColumn, + data: dataTableCell, + }: { + column: string; + data: any; + }): string => { + let cell: string[] | string | object; + // check truthiness to guard against _score, _type, etc if (tableColumn && dataTableCell) { try { cell = formatters[tableColumn].convert(dataTableCell); @@ -179,7 +185,12 @@ export class CsvGenerator { // We have to strip singular array values out of their array wrapper, // So that the value appears the visually the same as seen in Discover if (Array.isArray(cell)) { - cell = cell.join(', '); // mimic Discover behavior + cell = cell.map((c) => (typeof c === 'object' ? JSON.stringify(c) : c)).join(', '); + } + + // Check for object-type value (geoip) + if (typeof cell === 'object') { + cell = JSON.stringify(cell); } return cell; @@ -235,7 +246,7 @@ export class CsvGenerator { .join(settings.separator) + '\n'; if (!builder.tryAppend(row)) { - this.logger.warn('max Size Reached'); + this.logger.warn(`Max Size Reached after ${this.csvRowCount} rows.`); this.maxSizeReached = true; if (this.cancellationToken) { this.cancellationToken.cancel(); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security.config.ts b/x-pack/test/reporting_api_integration/reporting_and_security.config.ts index a1b0e8145391a..6627cb3be5ed5 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security.config.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security.config.ts @@ -42,7 +42,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--server.maxPayloadBytes=1679958`, `--server.port=${kbnTestConfig.getPort()}`, `--xpack.reporting.capture.maxAttempts=1`, - `--xpack.reporting.csv.maxSizeBytes=2850`, + `--xpack.reporting.csv.maxSizeBytes=6000`, `--xpack.reporting.queue.pollInterval=3000`, `--xpack.security.session.idleTimeout=3600000`, `--xpack.reporting.capture.networkPolicy.rules=${JSON.stringify(testPolicyRules)}`, diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 5013aa1b01e49..1056568bf1928 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -9,17 +9,35 @@ exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fi ], \\"\\"type\\"\\": \\"\\"Point\\"\\" }\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,,Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.99, 20.99\\",\\"20.99, 20.99\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.7, 9.87\\",\\"20.99, 20.99\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.99, 20.99\\",\\"20.99, 20.99\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.98\\",\\"41.98\\",2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,,Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.99, 32.99\\",\\"7.99, 32.99\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.48\\",\\"7.99, 32.99\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.99, 32.99\\",\\"7.99, 32.99\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.98\\",\\"40.98\\",2,2,order,brigitte +KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,,Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.99, 12.99\\",\\"28.99, 12.99\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.34, 6.11\\",\\"28.99, 12.99\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.99, 12.99\\",\\"28.99, 12.99\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.98\\",\\"41.98\\",2,2,order,abd " `; exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with almost all fields when using fieldsFromSource 1`] = ` "\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,currency,\\"customer_first_name\\",\\"customer_full_name\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,geoip,manufacturer,\\"order_date\\",\\"order_id\\",products,\\"products.created_on\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",[object Object],\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"[object Object], [object Object], [object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan -9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",[object Object],\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia -BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",[object Object],\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte -KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",EUR,Abd,\\"Abd Mccarthy\\",MALE,52,Mccarthy,\\"-\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",[object Object],\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\",41.98,41.98,2,2,order,abd -KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",EUR,Robert,\\"Robert Banks\\",MALE,29,Banks,\\"-\\",Saturday,5,\\"robert@banks-family.zzz\\",[object Object],\\"Elitelligence, Oceanavigations\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590976,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\",36.98,36.98,2,2,order,robert -awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,\\"Jim Hansen\\",MALE,41,Hansen,\\"-\\",Saturday,5,\\"jim@hansen-family.zzz\\",[object Object],\\"Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591636,\\"[object Object], [object Object]\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\",99.98,99.98,2,2,order,jim +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al Boone\\",MALE,19,Boone,\\"-\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"{\\"\\"city_name\\"\\":\\"\\"Abu Dhabi\\"\\",\\"\\"continent_name\\"\\":\\"\\"Asia\\"\\",\\"\\"country_iso_code\\"\\":\\"\\"AE\\"\\",\\"\\"location\\"\\":{\\"\\"lat\\"\\":24.5,\\"\\"lon\\"\\":54.4},\\"\\"region_name\\"\\":\\"\\"Abu Dhabi\\"\\"}\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"{\\"\\"_id\\"\\":\\"\\"sold_product_716724_23975\\"\\",\\"\\"base_price\\"\\":79.99,\\"\\"base_unit_price\\"\\":79.99,\\"\\"category\\"\\":\\"\\"Men's Shoes\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Angeldale\\"\\",\\"\\"min_price\\"\\":42.39,\\"\\"price\\"\\":79.99,\\"\\"product_id\\"\\":23975,\\"\\"product_name\\"\\":\\"\\"Winter boots - cognac\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0687606876\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":79.99,\\"\\"taxless_price\\"\\":79.99,\\"\\"unit_discount_amount\\"\\":0}, {\\"\\"_id\\"\\":\\"\\"sold_product_716724_6338\\"\\",\\"\\"base_price\\"\\":59.99,\\"\\"base_unit_price\\"\\":59.99,\\"\\"category\\"\\":\\"\\"Men's Clothing\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Oceanavigations\\"\\",\\"\\"min_price\\"\\":32.99,\\"\\"price\\"\\":59.99,\\"\\"product_id\\"\\":6338,\\"\\"product_name\\"\\":\\"\\"Trenchcoat - black\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0290502905\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":59.99,\\"\\"taxless_price\\"\\":59.99,\\"\\"unit_discount_amount\\"\\":0}, {\\"\\"_id\\"\\":\\"\\"sold_product_716724_14116\\"\\",\\"\\"base_price\\"\\":21.99,\\"\\"base_unit_price\\"\\":21.99,\\"\\"category\\"\\":\\"\\"Women's Accessories\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Microlutions\\"\\",\\"\\"min_price\\"\\":10.34,\\"\\"price\\"\\":21.99,\\"\\"product_id\\"\\":14116,\\"\\"product_name\\"\\":\\"\\"Watch - black\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0126701267\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":21.99,\\"\\"taxless_price\\"\\":21.99,\\"\\"unit_discount_amount\\"\\":0}, {\\"\\"_id\\"\\":\\"\\"sold_product_716724_15290\\"\\",\\"\\"base_price\\"\\":11.99,\\"\\"base_unit_price\\"\\":11.99,\\"\\"category\\"\\":\\"\\"Men's Accessories\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Oceanavigations\\"\\",\\"\\"min_price\\"\\":6.11,\\"\\"price\\"\\":11.99,\\"\\"product_id\\"\\":15290,\\"\\"product_name\\"\\":\\"\\"Hat - light grey multicolor\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0308503085\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":11.99,\\"\\"taxless_price\\"\\":11.99,\\"\\"unit_discount_amount\\"\\":0}\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",173.96,173.96,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,\\"Pia Richards\\",FEMALE,45,Richards,\\"-\\",Saturday,5,\\"pia@richards-family.zzz\\",\\"{\\"\\"city_name\\"\\":\\"\\"Cannes\\"\\",\\"\\"continent_name\\"\\":\\"\\"Europe\\"\\",\\"\\"country_iso_code\\"\\":\\"\\"FR\\"\\",\\"\\"location\\"\\":{\\"\\"lat\\"\\":43.6,\\"\\"lon\\"\\":7},\\"\\"region_name\\"\\":\\"\\"Alpes-Maritimes\\"\\"}\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"{\\"\\"_id\\"\\":\\"\\"sold_product_591503_14761\\"\\",\\"\\"base_price\\"\\":20.99,\\"\\"base_unit_price\\"\\":20.99,\\"\\"category\\"\\":\\"\\"Women's Shoes\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Tigress Enterprises\\"\\",\\"\\"min_price\\"\\":10.7,\\"\\"price\\"\\":20.99,\\"\\"product_id\\"\\":14761,\\"\\"product_name\\"\\":\\"\\"Classic heels - blue\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0006400064\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":20.99,\\"\\"taxless_price\\"\\":20.99,\\"\\"unit_discount_amount\\"\\":0}, {\\"\\"_id\\"\\":\\"\\"sold_product_591503_11632\\"\\",\\"\\"base_price\\"\\":20.99,\\"\\"base_unit_price\\"\\":20.99,\\"\\"category\\"\\":\\"\\"Women's Clothing\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Pyramidustries\\"\\",\\"\\"min_price\\"\\":9.87,\\"\\"price\\"\\":20.99,\\"\\"product_id\\"\\":11632,\\"\\"product_name\\"\\":\\"\\"Summer dress - coral/pink\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0150601506\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":20.99,\\"\\"taxless_price\\"\\":20.99,\\"\\"unit_discount_amount\\"\\":0}\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\",41.98,41.98,2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",EUR,Brigitte,\\"Brigitte Meyer\\",FEMALE,12,Meyer,\\"-\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"{\\"\\"city_name\\"\\":\\"\\"New York\\"\\",\\"\\"continent_name\\"\\":\\"\\"North America\\"\\",\\"\\"country_iso_code\\"\\":\\"\\"US\\"\\",\\"\\"location\\"\\":{\\"\\"lat\\"\\":40.8,\\"\\"lon\\"\\":-74},\\"\\"region_name\\"\\":\\"\\"New York\\"\\"}\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"{\\"\\"_id\\"\\":\\"\\"sold_product_591709_20734\\"\\",\\"\\"base_price\\"\\":7.99,\\"\\"base_unit_price\\"\\":7.99,\\"\\"category\\"\\":\\"\\"Women's Clothing\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Spherecords\\"\\",\\"\\"min_price\\"\\":3.6,\\"\\"price\\"\\":7.99,\\"\\"product_id\\"\\":20734,\\"\\"product_name\\"\\":\\"\\"Basic T-shirt - dark blue\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0638206382\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":7.99,\\"\\"taxless_price\\"\\":7.99,\\"\\"unit_discount_amount\\"\\":0}, {\\"\\"_id\\"\\":\\"\\"sold_product_591709_7539\\"\\",\\"\\"base_price\\"\\":32.99,\\"\\"base_unit_price\\"\\":32.99,\\"\\"category\\"\\":\\"\\"Women's Clothing\\"\\",\\"\\"created_on\\"\\":\\"\\"2016-12-31T00:00:00+00:00\\"\\",\\"\\"discount_amount\\"\\":0,\\"\\"discount_percentage\\"\\":0,\\"\\"manufacturer\\"\\":\\"\\"Tigress Enterprises\\"\\",\\"\\"min_price\\"\\":17.48,\\"\\"price\\"\\":32.99,\\"\\"product_id\\"\\":7539,\\"\\"product_name\\"\\":\\"\\"Summer dress - scarab\\"\\",\\"\\"quantity\\"\\":1,\\"\\"sku\\"\\":\\"\\"ZO0038800388\\"\\",\\"\\"tax_amount\\"\\":0,\\"\\"taxful_price\\"\\":32.99,\\"\\"taxless_price\\"\\":32.99,\\"\\"unit_discount_amount\\"\\":0}\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\",40.98,40.98,2,2,order,brigitte " `; @@ -94,6 +112,10 @@ exports[`Reporting APIs CSV Generation from SearchSource date formatting With fi \\"Sep 20, 2015 @ 10:20:40.189\\",\\"80.83.92.252\\",jpg \\"Sep 20, 2015 @ 10:20:27.012\\",\\"66.194.157.171\\",png \\"Sep 20, 2015 @ 10:20:24.450\\",\\"15.191.218.38\\",jpg +\\"Sep 20, 2015 @ 10:19:45.764\\",\\"199.113.69.162\\",jpg +\\"Sep 20, 2015 @ 10:19:43.754\\",\\"171.243.18.67\\",gif +\\"Sep 20, 2015 @ 10:19:41.208\\",\\"126.87.234.213\\",jpg +\\"Sep 20, 2015 @ 10:19:40.307\\",\\"78.216.173.242\\",css " `; @@ -154,6 +176,10 @@ exports[`Reporting APIs CSV Generation from SearchSource date formatting With fi \\"Sep 20, 2015 @ 03:20:40.189\\",\\"80.83.92.252\\",jpg \\"Sep 20, 2015 @ 03:20:27.012\\",\\"66.194.157.171\\",png \\"Sep 20, 2015 @ 03:20:24.450\\",\\"15.191.218.38\\",jpg +\\"Sep 20, 2015 @ 03:19:45.764\\",\\"199.113.69.162\\",jpg +\\"Sep 20, 2015 @ 03:19:43.754\\",\\"171.243.18.67\\",gif +\\"Sep 20, 2015 @ 03:19:41.208\\",\\"126.87.234.213\\",jpg +\\"Sep 20, 2015 @ 03:19:40.307\\",\\"78.216.173.242\\",css " `; @@ -199,5 +225,24 @@ exports[`Reporting APIs CSV Generation from SearchSource validation Searches lar \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" \\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,591803,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0645906459, ZO0324303243\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,592082,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0034400344, ZO0492904929\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,591283,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0239302393, ZO0198501985\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,591148,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0290302903, ZO0513705137\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,591417,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0464504645, ZO0621006210\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,591562,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0544305443, ZO0108001080\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,590996,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638106381, ZO0096900969\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,591317,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0139501395\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,591362,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0541805418, ZO0594105941\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,591411,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0693506935, ZO0532405324\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,722629,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0424204242, ZO0403504035, ZO0506705067, ZO0395603956\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,591041,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0418704187, ZO0557105571\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,591074,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0268602686, ZO0484704847\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,591349,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0474804748, ZO0560705607\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,591374,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0206002060, ZO0268302683\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591230,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0226902269, ZO0660106601\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,591717,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0248002480, ZO0646706467\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,591768,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0005800058, ZO0133901339\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,591810,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0587405874, ZO0590305903\\" " `; From 3bbce702905645288cf34495f026f381f2ce9329 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 14:13:26 -0700 Subject: [PATCH 44/51] remove client-side logic for sanitizing fields --- .../discover/public/application/helpers/get_sharing_data.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index de9d782c004fd..09d28e63d0dcf 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -40,12 +40,6 @@ export async function getSharingData( // fields get re-set to match the saved search columns let columns = state.columns || []; - // NOTE: A newly saved search with no columns selected will return a - // column array as a single '_source' value which is invalid for CSV export - if (columns && columns.length === 1 && /^_source$/.test(columns.join())) { - columns = []; - } - if (columns && columns.length > 0) { // conditionally add the time field column: let timeFieldName: string | undefined; From ae168981d2f1820eb253ae2807605149508fc0a6 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 14:21:23 -0700 Subject: [PATCH 45/51] do not prepend timefield name if it already is a column --- .../discover/public/application/helpers/get_sharing_data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.ts index 09d28e63d0dcf..f0e07ccc38deb 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.ts @@ -47,7 +47,7 @@ export async function getSharingData( if (!hideTimeColumn && index && index.timeFieldName) { timeFieldName = index.timeFieldName; } - if (timeFieldName) { + if (timeFieldName && !columns.includes(timeFieldName)) { columns = [timeFieldName, ...columns]; } From c7694f6e988cdf9439590045b9c8bf9007dbe721 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 14:31:57 -0700 Subject: [PATCH 46/51] test the logic to prepend timeField --- .../helpers/get_sharing_data.test.ts | 112 +++++++++++++++++- 1 file changed, 107 insertions(+), 5 deletions(-) diff --git a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts index 925576cee1596..ebb1946b524cd 100644 --- a/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/helpers/get_sharing_data.test.ts @@ -11,19 +11,29 @@ import { getSharingData, showPublicUrlSwitch } from './get_sharing_data'; import { IUiSettingsClient } from 'kibana/public'; import { createSearchSourceMock } from '../../../../data/common/search/search_source/mocks'; import { indexPatternMock } from '../../__mocks__/index_pattern'; -import { SORT_DEFAULT_ORDER_SETTING } from '../../../common'; +import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../common'; +import { IndexPattern } from 'src/plugins/data/public'; describe('getSharingData', () => { - test('returns valid data for sharing', async () => { - const searchSourceMock = createSearchSourceMock({ index: indexPatternMock }); - const result = await getSharingData(searchSourceMock, { columns: [] }, ({ + let mockConfig: IUiSettingsClient; + + beforeEach(() => { + mockConfig = ({ get: (key: string) => { if (key === SORT_DEFAULT_ORDER_SETTING) { return 'desc'; } + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return false; + } return false; }, - } as unknown) as IUiSettingsClient); + } as unknown) as IUiSettingsClient; + }); + + test('returns valid data for sharing', async () => { + const searchSourceMock = createSearchSourceMock({ index: indexPatternMock }); + const result = await getSharingData(searchSourceMock, { columns: [] }, mockConfig); expect(result).toMatchInlineSnapshot(` Object { "searchSource": Object { @@ -37,6 +47,98 @@ describe('getSharingData', () => { } `); }); + + test('fields have prepended timeField', async () => { + const index = { ...indexPatternMock } as IndexPattern; + index.timeFieldName = 'cool-timefield'; + + const searchSourceMock = createSearchSourceMock({ index }); + const result = await getSharingData( + searchSourceMock, + { + columns: [ + 'cool-field-1', + 'cool-field-2', + 'cool-field-3', + 'cool-field-4', + 'cool-field-5', + 'cool-field-6', + ], + }, + mockConfig + ); + expect(result).toMatchInlineSnapshot(` + Object { + "searchSource": Object { + "fields": Array [ + "cool-timefield", + "cool-field-1", + "cool-field-2", + "cool-field-3", + "cool-field-4", + "cool-field-5", + "cool-field-6", + ], + "index": "the-index-pattern-id", + "sort": Array [ + Object { + "_doc": "desc", + }, + ], + }, + } + `); + }); + + test('fields conditionally do not have prepended timeField', async () => { + mockConfig = ({ + get: (key: string) => { + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return true; + } + return false; + }, + } as unknown) as IUiSettingsClient; + + const index = { ...indexPatternMock } as IndexPattern; + index.timeFieldName = 'cool-timefield'; + + const searchSourceMock = createSearchSourceMock({ index }); + const result = await getSharingData( + searchSourceMock, + { + columns: [ + 'cool-field-1', + 'cool-field-2', + 'cool-field-3', + 'cool-field-4', + 'cool-field-5', + 'cool-field-6', + ], + }, + mockConfig + ); + expect(result).toMatchInlineSnapshot(` + Object { + "searchSource": Object { + "fields": Array [ + "cool-field-1", + "cool-field-2", + "cool-field-3", + "cool-field-4", + "cool-field-5", + "cool-field-6", + ], + "index": "the-index-pattern-id", + "sort": Array [ + Object { + "_doc": false, + }, + ], + }, + } + `); + }); }); describe('showPublicUrlSwitch', () => { From 9d871530ce508e65861db98b83a120726d20e14f Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 14:37:55 -0700 Subject: [PATCH 47/51] test the logic to sort the fields --- .../__snapshots__/generate_csv.test.ts.snap | 6 ++ .../generate_csv/generate_csv.test.ts | 64 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap index 6ec54a1c9c112..62c9ecff830ff 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/__snapshots__/generate_csv.test.ts.snap @@ -12,6 +12,12 @@ exports[`fields provides top-level underscored fields as columns 1`] = ` " `; +exports[`fields sorts the fields when they are to be used as table column names 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",date,\\"message_t\\",\\"message_u\\",\\"message_v\\",\\"message_w\\",\\"message_x\\",\\"message_y\\",\\"message_z\\" +\\"my-cool-id\\",\\"my-cool-index\\",\\"'-\\",\\"'-\\",\\"2020-12-31T00:14:28.000Z\\",\\"test field T\\",\\"test field U\\",\\"test field V\\",\\"test field W\\",\\"test field X\\",\\"test field Y\\",\\"test field Z\\" +" +`; + exports[`formats a search result to CSV content 1`] = ` "date,ip,message \\"2020-12-31T00:14:28.000Z\\",\\"110.135.176.89\\",\\"This is a great message!\\" diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts index 0e651c98ce06b..0193eaaff2c8d 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.test.ts @@ -431,6 +431,70 @@ describe('fields', () => { expect(csvResult.content).toMatchSnapshot(); expect(csvResult.csv_contains_formulas).toBe(false); }); + + it('sorts the fields when they are to be used as table column names', async () => { + searchSourceMock.getField = jest.fn().mockImplementation((key: string) => { + if (key === 'fields') { + return ['*']; + } + return mockSearchSourceGetFieldDefault(key); + }); + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + hits: { + hits: [ + { + _id: 'my-cool-id', + _index: 'my-cool-index', + _version: 4, + fields: { + date: ['2020-12-31T00:14:28.000Z'], + message_z: [`test field Z`], + message_y: [`test field Y`], + message_x: [`test field X`], + message_w: [`test field W`], + message_v: [`test field V`], + message_u: [`test field U`], + message_t: [`test field T`], + }, + }, + ], + total: 1, + }, + }, + }) + ); + + const generateCsv = new CsvGenerator( + createMockJob({ + searchSource: { + query: { query: '', language: 'kuery' }, + sort: [{ '@date': 'desc' }], + index: '93f4bc50-6662-11eb-98bc-f550e2308366', + fields: ['*'], + filter: [], + }, + }), + mockConfig, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, + new CancellationToken(), + logger + ); + + const csvResult = await generateCsv.generateData(); + + expect(csvResult.content).toMatchSnapshot(); + expect(csvResult.csv_contains_formulas).toBe(false); + }); }); describe('formulas', () => { From 249c70f05421feb0197a04eff9ad5983da6072f5 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 16:15:58 -0700 Subject: [PATCH 48/51] fix functional test --- .../reporting/__snapshots__/download_csv.snap | 62 +++++++------ .../discover/__snapshots__/reporting.snap | 93 ++++++++++--------- 2 files changed, 85 insertions(+), 70 deletions(-) diff --git a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap index 29ba0ab5b2be0..10384b865c82e 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap +++ b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap @@ -1,38 +1,44 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`dashboard Reporting Download CSV E-Commerce Data Download CSV export of a saved search panel 1`] = ` -"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a filtered CSV export of a saved search panel 1`] = ` -"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 15dd3256607d2..5ddef936b41ae 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,56 +1,65 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`discover Discover CSV Export Generate CSV: archived search generates a report with data 1`] = ` -"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; exports[`discover Discover CSV Export Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` -"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; exports[`discover Discover CSV Export Generate CSV: archived search generates a report with filtered data 1`] = ` -"\\"order_date\\",\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" +\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" " `; From c0b4f48f569d4a625e670a5be10eb73c60f2a6dd Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 16:52:10 -0700 Subject: [PATCH 49/51] preserve the error from data.search --- .../csv_searchsource/generate_csv/generate_csv.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 4df6c70fc0239..370fc42921acf 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -22,6 +22,7 @@ import { SearchFieldValue, tabifyDocs, } from '../../../../../../../src/plugins/data/common'; +import { KbnServerError } from '../../../../../../../src/plugins/kibana_utils/server'; import { CancellationToken } from '../../../../common'; import { CONTENT_TYPE_CSV } from '../../../../common/constants'; import { byteSizeValueToNumber } from '../../../../common/schema_utils'; @@ -365,6 +366,9 @@ export class CsvGenerator { } } catch (err) { this.logger.error(err); + if (err instanceof KbnServerError && err.errBody) { + throw JSON.stringify(err.errBody.error); + } } finally { // clear scrollID if (scrollId) { From 78d9a8a25da6ffe737ad435f38f1b654e7ddaedf Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 17:06:06 -0700 Subject: [PATCH 50/51] add functional test for ES returning an error --- .../csv_searchsource_immediate.snap | 2 + .../csv_searchsource_immediate.ts | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 1056568bf1928..288e7869c0606 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -41,6 +41,8 @@ BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",EUR,Brigit " `; +exports[`Reporting APIs CSV Generation from SearchSource Fails with an explanation if the search throws an error 1`] = `"{\\"statusCode\\":500,\\"error\\":\\"Internal Server Error\\",\\"message\\":\\"An internal server error occurred.\\"}"`; + exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, UTC timezone 1`] = ` "date,message \\"Jan 1, 2015 @ 12:10:30.123456789\\",\\"Hello 2\\" diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts index 2b0d01b6f5f5e..27c6a05f740bf 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts @@ -197,6 +197,48 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload('reporting/ecommerce_kibana'); }); + it('Logs the error explanation if the search query returns an error', async () => { + await esArchiver.load('reporting/ecommerce'); + await esArchiver.load('reporting/ecommerce_kibana'); + + const { status: resStatus, text: resText } = (await generateAPI.getCSVFromSearchSource( + getMockJobParams({ + searchSource: { + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], + fields: ['order_date', 'products'], // products is a non-leaf field + filter: [], + parent: { + query: { language: 'kuery', query: '' }, + filter: [], + parent: { + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: '2019-03-23T03:06:17.785Z', + lte: '2019-10-04T02:33:16.708Z', + format: 'strict_date_optional_time', + }, + }, + }, + ], + }, + }, + }, + browserTimezone: 'UTC', + title: 'testfooyu78yt90-', + }) + )) as supertest.Response; + expect(resStatus).to.eql(500); + expectSnapshot(resText).toMatch(); + + await esArchiver.unload('reporting/ecommerce'); + await esArchiver.unload('reporting/ecommerce_kibana'); + }); + describe('date formatting', () => { before(async () => { // load test data that contains a saved search and documents From d786783c9dedfe8830df4ce4a615b2dbf5e6d851 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 15 Mar 2021 20:25:57 -0700 Subject: [PATCH 51/51] fix snapshot --- .../__snapshots__/csv_searchsource_immediate.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap index 288e7869c0606..c7ef39f65f552 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap @@ -41,7 +41,7 @@ BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",EUR,Brigit " `; -exports[`Reporting APIs CSV Generation from SearchSource Fails with an explanation if the search throws an error 1`] = `"{\\"statusCode\\":500,\\"error\\":\\"Internal Server Error\\",\\"message\\":\\"An internal server error occurred.\\"}"`; +exports[`Reporting APIs CSV Generation from SearchSource Logs the error explanation if the search query returns an error 1`] = `"{\\"statusCode\\":500,\\"error\\":\\"Internal Server Error\\",\\"message\\":\\"An internal server error occurred.\\"}"`; exports[`Reporting APIs CSV Generation from SearchSource date formatting Formatted date_nanos data, UTC timezone 1`] = ` "date,message