From ae9cbfcb27b298380a7495033562b4f2e5bbb872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Thu, 30 Jan 2020 12:11:38 +0530 Subject: [PATCH 03/69] [Mappings editor] Bring improvements from #55804 PR to master (#56282) --- .../helpers/mappings_editor.helpers.ts | 2 +- .../mappings_editor.test.tsx | 4 +- .../load_mappings_provider.test.tsx | 77 +++++++++++++++++++ .../load_mappings/load_mappings_provider.tsx | 2 +- .../lib/extract_mappings_definition.ts | 9 +-- .../lib/mappings_validator.test.ts | 26 ++++++- .../mappings_editor/lib/mappings_validator.ts | 74 +++++++++++++----- 7 files changed, 159 insertions(+), 35 deletions(-) create mode 100644 x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts index b8b67a0f36bd2e..dcee956130a29f 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts @@ -13,4 +13,4 @@ export const setup = (props: any) => wrapComponent: false, }, defaultProps: props, - }); + })(); diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx index 9e390e785c7d56..723c105d403b84 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx @@ -28,7 +28,7 @@ describe('', () => { }, }, }; - const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue })(); + const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue }); const { exists } = testBed; expect(exists('mappingsEditor')).toBe(true); @@ -44,7 +44,7 @@ describe('', () => { }, }, }; - const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue })(); + const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue }); const { exists } = testBed; expect(exists('mappingsEditor')).toBe(true); diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx new file mode 100644 index 00000000000000..a9433d3a7530ff --- /dev/null +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { act } from 'react-dom/test-utils'; + +jest.mock('@elastic/eui', () => ({ + ...jest.requireActual('@elastic/eui'), + // Mocking EuiCodeEditor, which uses React Ace under the hood + EuiCodeEditor: (props: any) => ( + { + props.onChange(syntheticEvent.jsonString); + }} + /> + ), +})); + +import { registerTestBed, nextTick, TestBed } from '../../../../../../../../../test_utils'; +import { LoadMappingsProvider } from './load_mappings_provider'; + +const ComponentToTest = ({ onJson }: { onJson: () => void }) => ( + + {openModal => ( + + )} + +); + +const setup = (props: any) => + registerTestBed(ComponentToTest, { + memoryRouter: { wrapComponent: false }, + defaultProps: props, + })(); + +const openModalWithJsonContent = ({ find, component }: TestBed) => async (json: any) => { + find('load-json-button').simulate('click'); + component.update(); + + // Set the mappings to load + // @ts-ignore + await act(async () => { + find('mockCodeEditor').simulate('change', { + jsonString: JSON.stringify(json), + }); + await nextTick(300); // There is a debounce in the JsonEditor that we need to wait for + }); +}; + +describe('', () => { + test('it should forward valid mapping definition', async () => { + const mappingsToLoad = { + properties: { + title: { + type: 'text', + }, + }, + }; + + const onJson = jest.fn(); + const testBed = await setup({ onJson }); + + // Open the modal and add the JSON + await openModalWithJsonContent(testBed)(mappingsToLoad); + + // Confirm + testBed.find('confirmModalConfirmButton').simulate('click'); + + const [jsonReturned] = onJson.mock.calls[0]; + expect(jsonReturned).toEqual({ ...mappingsToLoad, dynamic_templates: [] }); + }); +}); diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx index a55bd96dce3d03..6bc360a1ec70e2 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx @@ -25,7 +25,7 @@ type OpenJsonModalFunc = () => void; interface Props { onJson(json: { [key: string]: any }): void; - children: (deleteProperty: OpenJsonModalFunc) => React.ReactNode; + children: (openModal: OpenJsonModalFunc) => React.ReactNode; } interface State { diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/extract_mappings_definition.ts b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/extract_mappings_definition.ts index eae3c5b15759ca..817b0f4a4d3d0b 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/extract_mappings_definition.ts +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/extract_mappings_definition.ts @@ -6,15 +6,10 @@ import { isPlainObject } from 'lodash'; import { GenericObject } from '../types'; -import { - validateMappingsConfiguration, - mappingsConfigurationSchemaKeys, -} from './mappings_validator'; - -const ALLOWED_PARAMETERS = [...mappingsConfigurationSchemaKeys, 'dynamic_templates', 'properties']; +import { validateMappingsConfiguration, VALID_MAPPINGS_PARAMETERS } from './mappings_validator'; const isMappingDefinition = (obj: GenericObject): boolean => { - const areAllKeysValid = Object.keys(obj).every(key => ALLOWED_PARAMETERS.includes(key)); + const areAllKeysValid = Object.keys(obj).every(key => VALID_MAPPINGS_PARAMETERS.includes(key)); if (!areAllKeysValid) { return false; diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.test.ts b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.test.ts index f1e6efb06c6492..d67c267dda6aec 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.test.ts +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.test.ts @@ -18,6 +18,24 @@ describe('Mappings configuration validator', () => { }); }); + it('should detect valid mappings configuration', () => { + const mappings = { + _source: { + includes: [], + excludes: [], + enabled: true, + }, + _meta: {}, + _routing: { + required: false, + }, + dynamic: true, + }; + + const { errors } = validateMappings(mappings); + expect(errors).toBe(undefined); + }); + it('should strip out unknown configuration', () => { const mappings = { dynamic: true, @@ -30,6 +48,7 @@ describe('Mappings configuration validator', () => { excludes: ['abc'], }, properties: { title: { type: 'text' } }, + dynamic_templates: [], unknown: 123, }; @@ -37,7 +56,7 @@ describe('Mappings configuration validator', () => { const { unknown, ...expected } = mappings; expect(value).toEqual(expected); - expect(errors).toBe(undefined); + expect(errors).toEqual([{ code: 'ERR_CONFIG', configName: 'unknown' }]); }); it('should strip out invalid configuration and returns the errors for each of them', () => { @@ -47,9 +66,8 @@ describe('Mappings configuration validator', () => { dynamic_date_formats: false, // wrong format _source: { enabled: true, - includes: 'abc', + unknownProp: 'abc', // invalid excludes: ['abc'], - wrong: 123, // parameter not allowed }, properties: 'abc', }; @@ -59,10 +77,10 @@ describe('Mappings configuration validator', () => { expect(value).toEqual({ dynamic: true, properties: {}, + dynamic_templates: [], }); expect(errors).not.toBe(undefined); - expect(errors!.length).toBe(3); expect(errors!).toEqual([ { code: 'ERR_CONFIG', configName: '_source' }, { code: 'ERR_CONFIG', configName: 'dynamic_date_formats' }, diff --git a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.ts b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.ts index 6ccbfeb50dcf44..78d638e3985932 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.ts +++ b/x-pack/legacy/plugins/index_management/public/app/components/mappings_editor/lib/mappings_validator.ts @@ -196,23 +196,30 @@ export const validateProperties = (properties = {}): PropertiesValidatorResponse * Single source of truth to validate the *configuration* of the mappings. * Whenever a user loads a JSON object it will be validate against this Joi schema. */ -export const mappingsConfigurationSchema = t.partial({ - dynamic: t.union([t.literal(true), t.literal(false), t.literal('strict')]), - date_detection: t.boolean, - numeric_detection: t.boolean, - dynamic_date_formats: t.array(t.string), - _source: t.partial({ - enabled: t.boolean, - includes: t.array(t.string), - excludes: t.array(t.string), - }), - _meta: t.UnknownRecord, - _routing: t.partial({ - required: t.boolean, - }), -}); - -export const mappingsConfigurationSchemaKeys = Object.keys(mappingsConfigurationSchema.props); +export const mappingsConfigurationSchema = t.exact( + t.partial({ + dynamic: t.union([t.literal(true), t.literal(false), t.literal('strict')]), + date_detection: t.boolean, + numeric_detection: t.boolean, + dynamic_date_formats: t.array(t.string), + _source: t.exact( + t.partial({ + enabled: t.boolean, + includes: t.array(t.string), + excludes: t.array(t.string), + }) + ), + _meta: t.UnknownRecord, + _routing: t.interface({ + required: t.boolean, + }), + }) +); + +const mappingsConfigurationSchemaKeys = Object.keys(mappingsConfigurationSchema.type.props); +const sourceConfigurationSchemaKeys = Object.keys( + mappingsConfigurationSchema.type.props._source.type.props +); export const validateMappingsConfiguration = ( mappingsConfiguration: any @@ -222,8 +229,20 @@ export const validateMappingsConfiguration = ( let copyOfMappingsConfig = { ...mappingsConfiguration }; const result = mappingsConfigurationSchema.decode(mappingsConfiguration); + const isSchemaInvalid = isLeft(result); - if (isLeft(result)) { + const unknownConfigurationParameters = Object.keys(mappingsConfiguration).filter( + key => mappingsConfigurationSchemaKeys.includes(key) === false + ); + + const unknownSourceConfigurationParameters = + mappingsConfiguration._source !== undefined + ? Object.keys(mappingsConfiguration._source).filter( + key => sourceConfigurationSchemaKeys.includes(key) === false + ) + : []; + + if (isSchemaInvalid) { /** * To keep the logic simple we will strip out the parameters that contain errors */ @@ -235,6 +254,15 @@ export const validateMappingsConfiguration = ( }); } + if (unknownConfigurationParameters.length > 0) { + unknownConfigurationParameters.forEach(configName => configurationRemoved.add(configName)); + } + + if (unknownSourceConfigurationParameters.length > 0) { + configurationRemoved.add('_source'); + delete copyOfMappingsConfig._source; + } + copyOfMappingsConfig = pick(copyOfMappingsConfig, mappingsConfigurationSchemaKeys); const errors: MappingsValidationError[] = toArray(ordString)(configurationRemoved) @@ -252,7 +280,7 @@ export const validateMappings = (mappings: any = {}): MappingsValidatorResponse return { value: {} }; } - const { properties, dynamic_templates, ...mappingsConfiguration } = mappings; + const { properties, dynamic_templates: dynamicTemplates, ...mappingsConfiguration } = mappings; const { value: parsedConfiguration, errors: configurationErrors } = validateMappingsConfiguration( mappingsConfiguration @@ -265,8 +293,14 @@ export const validateMappings = (mappings: any = {}): MappingsValidatorResponse value: { ...parsedConfiguration, properties: parsedProperties, - dynamic_templates, + dynamic_templates: dynamicTemplates ?? [], }, errors: errors.length ? errors : undefined, }; }; + +export const VALID_MAPPINGS_PARAMETERS = [ + ...mappingsConfigurationSchemaKeys, + 'dynamic_templates', + 'properties', +]; From 326afbc304653123277c82ed82570f592aba39ac Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 30 Jan 2020 08:01:40 +0100 Subject: [PATCH 04/69] [Uptime] In Ping histogram use auto date histogram (#55605) * update ping histogram API * update test * fix tests * update test * unused code Co-authored-by: Elastic Machine --- .../uptime/common/domain_types/monitors.ts | 7 - .../uptime/common/graphql/introspection.json | 137 ------------- .../plugins/uptime/common/graphql/types.ts | 86 -------- .../plugins/uptime/common/types/index.ts | 7 + .../uptime/common/types/ping/histogram.ts | 32 +++ .../connected/charts/ping_histogram.tsx | 76 +++++++ .../public/components/connected/index.ts | 7 + .../__snapshots__/chart_wrapper.test.tsx.snap | 8 +- .../ping_histogram.test.tsx.snap | 48 +++++ .../snapshot_histogram.test.tsx.snap | 7 - ...ogram.test.tsx => ping_histogram.test.tsx} | 9 +- .../charts/chart_wrapper/chart_wrapper.tsx | 8 +- .../components/functional/charts/index.ts | 2 +- ...pshot_histogram.tsx => ping_histogram.tsx} | 47 ++--- .../public/components/functional/index.ts | 2 +- .../components/functional/monitor_charts.tsx | 8 +- .../components/functional/status_panel.tsx | 11 +- .../plugins/uptime/public/pages/overview.tsx | 1 - .../queries/snapshot_histogram_query.ts | 38 ---- .../uptime/public/state/actions/index.ts | 1 + .../uptime/public/state/actions/ping.ts | 12 ++ .../plugins/uptime/public/state/api/index.ts | 1 + .../uptime/public/state/api/monitor.ts | 6 +- .../plugins/uptime/public/state/api/ping.ts | 35 ++++ .../plugins/uptime/public/state/api/types.ts | 2 + .../uptime/public/state/effects/index.ts | 2 + .../uptime/public/state/effects/ping.ts | 17 ++ .../uptime/public/state/reducers/index.ts | 2 + .../uptime/public/state/reducers/ping.ts | 45 +++++ .../state/selectors/__tests__/index.test.ts | 5 + .../uptime/public/state/selectors/index.ts | 4 + .../server/graphql/monitors/resolvers.ts | 42 +--- .../server/graphql/monitors/schema.gql.ts | 26 --- .../elasticsearch_pings_adapter.test.ts.snap | 12 +- .../elasticsearch_pings_adapter.test.ts | 48 ++--- .../adapters/pings/es_get_ping_historgram.ts | 82 ++++++++ ...ticsearch_pings_adapter.ts => es_pings.ts} | 80 +------- .../uptime/server/lib/adapters/pings/index.ts | 4 +- .../pings/{adapter_types.ts => types.ts} | 15 +- .../server/lib/helper/assert_close_to.ts | 5 + .../plugins/uptime/server/lib/helper/index.ts | 1 - .../plugins/uptime/server/rest_api/index.ts | 2 + .../rest_api/pings/get_ping_histogram.ts | 44 ++++ .../graphql/fixtures/snapshot_histogram.json | 188 ------------------ .../snapshot_histogram_by_filter.json | 188 ------------------ .../fixtures/snapshot_histogram_by_id.json | 188 ------------------ .../apis/uptime/graphql/index.js | 1 - .../apis/uptime/graphql/snapshot_histogram.ts | 88 -------- .../uptime/rest/fixtures/ping_histogram.json | 24 +++ .../fixtures/ping_histogram_by_filter.json | 24 +++ .../rest/fixtures/ping_histogram_by_id.json | 24 +++ .../api_integration/apis/uptime/rest/index.ts | 1 + .../apis/uptime/rest/ping_histogram.ts | 64 ++++++ 53 files changed, 644 insertions(+), 1180 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/common/types/index.ts create mode 100644 x-pack/legacy/plugins/uptime/common/types/ping/histogram.ts create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/index.ts create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap delete mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap rename x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/{snapshot_histogram.test.tsx => ping_histogram.test.tsx} (64%) rename x-pack/legacy/plugins/uptime/public/components/functional/charts/{snapshot_histogram.tsx => ping_histogram.tsx} (76%) delete mode 100644 x-pack/legacy/plugins/uptime/public/queries/snapshot_histogram_query.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/actions/ping.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/api/ping.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/effects/ping.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts create mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_get_ping_historgram.ts rename x-pack/legacy/plugins/uptime/server/lib/adapters/pings/{elasticsearch_pings_adapter.ts => es_pings.ts} (67%) rename x-pack/legacy/plugins/uptime/server/lib/adapters/pings/{adapter_types.ts => types.ts} (79%) create mode 100644 x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts delete mode 100644 x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram.json delete mode 100644 x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_filter.json delete mode 100644 x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_id.json delete mode 100644 x-pack/test/api_integration/apis/uptime/graphql/snapshot_histogram.ts create mode 100644 x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram.json create mode 100644 x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_filter.json create mode 100644 x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_id.json create mode 100644 x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts diff --git a/x-pack/legacy/plugins/uptime/common/domain_types/monitors.ts b/x-pack/legacy/plugins/uptime/common/domain_types/monitors.ts index 296df279b8eec9..7f5699eb7e8a4e 100644 --- a/x-pack/legacy/plugins/uptime/common/domain_types/monitors.ts +++ b/x-pack/legacy/plugins/uptime/common/domain_types/monitors.ts @@ -4,14 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HistogramDataPoint } from '../graphql/types'; - export interface UMGqlRange { dateRangeStart: string; dateRangeEnd: string; } - -export interface HistogramResult { - histogram: HistogramDataPoint[]; - interval: number; -} diff --git a/x-pack/legacy/plugins/uptime/common/graphql/introspection.json b/x-pack/legacy/plugins/uptime/common/graphql/introspection.json index 19d9cf19cc7f84..e5d9816ebd28e8 100644 --- a/x-pack/legacy/plugins/uptime/common/graphql/introspection.json +++ b/x-pack/legacy/plugins/uptime/common/graphql/introspection.json @@ -166,65 +166,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "getSnapshotHistogram", - "description": "", - "args": [ - { - "name": "dateRangeStart", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "dateRangeEnd", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filters", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "statusFilter", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "monitorId", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HistogramDataPoint", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "getMonitorChartsData", "description": "", @@ -2172,57 +2113,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "HistogramDataPoint", - "description": "", - "fields": [ - { - "name": "upCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "downCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "x", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "x0", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "MonitorChart", @@ -3944,33 +3834,6 @@ ], "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "DataPoint", - "description": "", - "fields": [ - { - "name": "x", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "MonitorDurationAreaPoint", diff --git a/x-pack/legacy/plugins/uptime/common/graphql/types.ts b/x-pack/legacy/plugins/uptime/common/graphql/types.ts index 92e27d20323a76..c58dd9111cc3f7 100644 --- a/x-pack/legacy/plugins/uptime/common/graphql/types.ts +++ b/x-pack/legacy/plugins/uptime/common/graphql/types.ts @@ -24,8 +24,6 @@ export interface Query { getSnapshot?: Snapshot | null; - getSnapshotHistogram: HistogramDataPoint[]; - getMonitorChartsData?: MonitorChart | null; /** Fetch the most recent event data for a monitor ID, date range, location. */ getLatestMonitors: Ping[]; @@ -419,17 +417,7 @@ export interface SnapshotCount { total: number; } -export interface HistogramDataPoint { - upCount?: number | null; - - downCount?: number | null; - - x?: UnsignedInteger | null; - - x0?: UnsignedInteger | null; - y?: UnsignedInteger | null; -} /** The data used to populate the monitor charts. */ export interface MonitorChart { /** The average values for the monitor duration. */ @@ -616,47 +604,6 @@ export interface StatesIndexStatus { docCount?: DocCount | null; } -export interface DataPoint { - x?: UnsignedInteger | null; - - y?: number | null; -} -/** Represents a monitor's duration performance in microseconds at a point in time. */ -export interface MonitorDurationAreaPoint { - /** The timeseries value for this point in time. */ - x: UnsignedInteger; - /** The min duration value in microseconds at this time. */ - yMin?: number | null; - /** The max duration value in microseconds at this point. */ - yMax?: number | null; -} - -export interface MonitorSummaryUrl { - domain?: string | null; - - fragment?: string | null; - - full?: string | null; - - original?: string | null; - - password?: string | null; - - path?: string | null; - - port?: number | null; - - query?: string | null; - - scheme?: string | null; - - username?: string | null; -} - -// ==================================================== -// Arguments -// ==================================================== - export interface AllPingsQueryArgs { /** Optional: the direction to sort by. Accepts 'asc' and 'desc'. Defaults to 'desc'. */ sort?: string | null; @@ -673,35 +620,7 @@ export interface AllPingsQueryArgs { /** Optional: agent location to filter by. */ location?: string | null; } -export interface GetMonitorsQueryArgs { - dateRangeStart: string; - - dateRangeEnd: string; - - filters?: string | null; - - statusFilter?: string | null; -} -export interface GetSnapshotQueryArgs { - dateRangeStart: string; - - dateRangeEnd: string; - - filters?: string | null; - statusFilter?: string | null; -} -export interface GetSnapshotHistogramQueryArgs { - dateRangeStart: string; - - dateRangeEnd: string; - - filters?: string | null; - - statusFilter?: string | null; - - monitorId?: string | null; -} export interface GetMonitorChartsDataQueryArgs { monitorId: string; @@ -711,11 +630,6 @@ export interface GetMonitorChartsDataQueryArgs { location?: string | null; } -export interface GetFilterBarQueryArgs { - dateRangeStart: string; - - dateRangeEnd: string; -} export interface GetMonitorStatesQueryArgs { dateRangeStart: string; diff --git a/x-pack/legacy/plugins/uptime/common/types/index.ts b/x-pack/legacy/plugins/uptime/common/types/index.ts new file mode 100644 index 00000000000000..34bfbc540672f1 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/common/types/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './ping/histogram'; diff --git a/x-pack/legacy/plugins/uptime/common/types/ping/histogram.ts b/x-pack/legacy/plugins/uptime/common/types/ping/histogram.ts new file mode 100644 index 00000000000000..7ac8d1f7b01510 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/common/types/ping/histogram.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export type UnsignedInteger = any; + +export interface HistogramDataPoint { + upCount?: number | null; + + downCount?: number | null; + + x?: UnsignedInteger | null; + + x0?: UnsignedInteger | null; + + y?: UnsignedInteger | null; +} + +export interface GetPingHistogramParams { + dateStart: string; + dateEnd: string; + filters?: string; + monitorId?: string; + statusFilter?: string; +} + +export interface HistogramResult { + histogram: HistogramDataPoint[]; + interval: string; +} diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx new file mode 100644 index 00000000000000..a6607ca81fc183 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { AppState } from '../../../state'; +import { + PingHistogramComponent, + PingHistogramComponentProps, +} from '../../functional/charts/ping_histogram'; +import { getPingHistogram } from '../../../state/actions'; +import { selectPingHistogram } from '../../../state/selectors'; +import { withResponsiveWrapper, ResponsiveWrapperProps } from '../../higher_order'; +import { GetPingHistogramParams, HistogramResult } from '../../../../common/types'; + +type Props = GetPingHistogramParams & + ResponsiveWrapperProps & + PingHistogramComponentProps & + DispatchProps & { lastRefresh: number }; + +const PingHistogramContainer: React.FC = ({ + data, + loadData, + statusFilter, + filters, + dateStart, + dateEnd, + absoluteStartDate, + absoluteEndDate, + monitorId, + lastRefresh, + ...props +}) => { + useEffect(() => { + loadData({ monitorId, dateStart, dateEnd, statusFilter, filters }); + }, [loadData, dateStart, dateEnd, monitorId, filters, statusFilter, lastRefresh]); + return ( + + ); +}; + +interface StateProps { + data: HistogramResult | null; + loading: boolean; + lastRefresh: number; +} + +interface DispatchProps { + loadData: typeof getPingHistogram; +} + +const mapStateToProps = (state: AppState): StateProps => ({ ...selectPingHistogram(state) }); + +const mapDispatchToProps = (dispatch: any): DispatchProps => ({ + loadData: (params: GetPingHistogramParams) => { + return dispatch(getPingHistogram(params)); + }, +}); + +export const PingHistogram = connect< + StateProps, + DispatchProps, + PingHistogramComponentProps, + AppState +>( + mapStateToProps, + mapDispatchToProps +)(withResponsiveWrapper(PingHistogramContainer)); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/index.ts b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts new file mode 100644 index 00000000000000..f9f6aa263ed270 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PingHistogram } from './charts/ping_histogram'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap index 3f3e6b0b929e12..c1b5970f6456cc 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ChartWrapper component renders the component with loading false 1`] = ` - +
-
+ `; exports[`ChartWrapper component renders the component with loading true 1`] = ` - +
- + `; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap new file mode 100644 index 00000000000000..8ee4dc3575469d --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PingHistogram component renders the component without errors 1`] = ` + + +
+ +
+
+ + + +

+ } + title={ + +
+ +
+
+ } + /> +
+
+`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap deleted file mode 100644 index a725f97d3e0fbf..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SnapshotHistogram component renders the component without errors 1`] = ` - - - -`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/snapshot_histogram.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/ping_histogram.test.tsx similarity index 64% rename from x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/snapshot_histogram.test.tsx rename to x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/ping_histogram.test.tsx index db78c063b7ed58..de7cfc86abc0cc 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/snapshot_histogram.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/ping_histogram.test.tsx @@ -6,17 +6,16 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { SnapshotHistogram, SnapshotHistogramProps } from '../snapshot_histogram'; +import { PingHistogramComponent, PingHistogramComponentProps } from '../ping_histogram'; -describe('SnapshotHistogram component', () => { - const props: SnapshotHistogramProps = { +describe('PingHistogram component', () => { + const props: PingHistogramComponentProps = { absoluteStartDate: 1548697920000, absoluteEndDate: 1548700920000, - isResponsive: false, }; it('renders the component without errors', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/chart_wrapper/chart_wrapper.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/chart_wrapper/chart_wrapper.tsx index deeb1411052c3d..7286c599568873 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/chart_wrapper/chart_wrapper.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/chart_wrapper/chart_wrapper.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, Fragment, HTMLAttributes } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiLoadingChart } from '@elastic/eui'; +import React, { FC, HTMLAttributes } from 'react'; +import { EuiErrorBoundary, EuiFlexGroup, EuiFlexItem, EuiLoadingChart } from '@elastic/eui'; interface Props { /** @@ -31,7 +31,7 @@ export const ChartWrapper: FC = ({ const opacity = loading === true ? 0.3 : 1; return ( - +
= ({ )} - + ); }; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/charts/index.ts index f7c1283dc9e072..2cbd9a2b3aa324 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/index.ts @@ -7,4 +7,4 @@ export { DonutChart } from './donut_chart'; export { DurationChart } from './duration_chart'; export { MonitorBarSeries } from './monitor_bar_series'; -export { SnapshotHistogram } from './snapshot_histogram'; +export { PingHistogramComponent } from './ping_histogram'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/snapshot_histogram.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx similarity index 76% rename from x-pack/legacy/plugins/uptime/public/components/functional/charts/snapshot_histogram.tsx rename to x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx index 92b04534b73310..2d44cff0108cd9 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/snapshot_histogram.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/ping_histogram.tsx @@ -4,21 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Axis, BarSeries, Chart, Position, timeFormatter, Settings } from '@elastic/charts'; -import { EuiEmptyPrompt, EuiTitle, EuiPanel } from '@elastic/eui'; +import { Axis, BarSeries, Chart, Position, Settings, timeFormatter } from '@elastic/charts'; +import { EuiEmptyPrompt, EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useContext } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import moment from 'moment'; import { getChartDateLabel } from '../../../lib/helper'; -import { withUptimeGraphQL, UptimeGraphQLQueryProps } from '../../higher_order'; -import { snapshotHistogramQuery } from '../../../queries/snapshot_histogram_query'; import { ChartWrapper } from './chart_wrapper'; import { UptimeThemeContext } from '../../../contexts'; -import { ResponsiveWrapperProps, withResponsiveWrapper } from '../../higher_order'; -import { HistogramResult } from '../../../../common/domain_types'; +import { HistogramResult } from '../../../../common/types'; -interface HistogramProps { +export interface PingHistogramComponentProps { /** * The date/time for the start of the timespan. */ @@ -32,29 +29,23 @@ interface HistogramProps { * Height is needed, since by default charts takes height of 100% */ height?: string; -} -export type SnapshotHistogramProps = HistogramProps & ResponsiveWrapperProps; + data?: HistogramResult; -interface SnapshotHistogramQueryResult { - queryResult?: HistogramResult; + loading?: boolean; } -type Props = UptimeGraphQLQueryProps & - SnapshotHistogramProps & - ResponsiveWrapperProps; - -export const SnapshotHistogramComponent: React.FC = ({ +export const PingHistogramComponent: React.FC = ({ absoluteStartDate, absoluteEndDate, data, loading = false, height, -}: Props) => { +}) => { const { colors: { danger, gray }, } = useContext(UptimeThemeContext); - if (!data || !data.queryResult) + if (!data || !data.histogram) /** * TODO: the Fragment, EuiTitle, and EuiPanel should be extracted to a dumb component * that we can reuse in the subsequent return statement at the bottom of this function. @@ -93,19 +84,15 @@ export const SnapshotHistogramComponent: React.FC = ({ ); - const { - queryResult: { histogram, interval }, - } = data; + const { histogram } = data; - const downMonitorsId = i18n.translate('xpack.uptime.snapshotHistogram.downMonitorsId', { + const downSpecId = i18n.translate('xpack.uptime.snapshotHistogram.downMonitorsId', { defaultMessage: 'Down Monitors', }); - const downSpecId = downMonitorsId; const upMonitorsId = i18n.translate('xpack.uptime.snapshotHistogram.series.upLabel', { defaultMessage: 'Up', }); - const upSpecId = upMonitorsId; return ( <> @@ -131,7 +118,6 @@ export const SnapshotHistogramComponent: React.FC = ({ = ({ /> = ({ /> = ({ [x, upCount || 0])} - id={upSpecId} + id={upMonitorsId} name={upMonitorsId} stackAccessors={[0]} timeZone="local" @@ -187,8 +173,3 @@ export const SnapshotHistogramComponent: React.FC = ({ ); }; - -export const SnapshotHistogram = withUptimeGraphQL< - SnapshotHistogramQueryResult, - SnapshotHistogramProps ->(withResponsiveWrapper(SnapshotHistogramComponent), snapshotHistogramQuery); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts index 7370faa12f3939..b9f0014322062d 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts @@ -15,5 +15,5 @@ export { MonitorList } from './monitor_list'; export { OverviewPageParsingErrorCallout } from './overview_page_parsing_error_callout'; export { PingList } from './ping_list'; export { Snapshot } from './snapshot'; -export { SnapshotHistogram } from './charts'; +export { PingHistogramComponent } from './charts'; export { StatusPanel } from './status_panel'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_charts.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_charts.tsx index 809618f07a6c1d..ae99d08ab634e0 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_charts.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_charts.tsx @@ -11,8 +11,8 @@ import { MonitorChart } from '../../../common/graphql/types'; import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order'; import { monitorChartsQuery } from '../../queries'; import { DurationChart } from './charts'; -import { SnapshotHistogram } from './charts/snapshot_histogram'; import { useUrlParams } from '../../hooks'; +import { PingHistogram } from '../connected'; interface MonitorChartsQueryResult { monitorChartsData?: MonitorChart; @@ -58,12 +58,14 @@ export const MonitorChartsComponent = ({ /> - diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx index b74bc943dc3eb7..03ab9fb5cf194b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx @@ -6,8 +6,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import React from 'react'; -import { SnapshotHistogram } from './charts'; import { Snapshot } from './snapshot'; +import { PingHistogram } from '../connected'; interface StatusPanelProps { absoluteDateRangeStart: number; @@ -16,7 +16,6 @@ interface StatusPanelProps { dateRangeEnd: string; filters?: string; statusFilter?: string; - sharedProps: { [key: string]: any }; } const STATUS_CHART_HEIGHT = '160px'; @@ -28,7 +27,6 @@ export const StatusPanel = ({ dateRangeEnd, filters, statusFilter, - sharedProps, }: StatusPanelProps) => ( @@ -42,12 +40,15 @@ export const StatusPanel = ({ /> - diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index 36abee673b6829..b9c2284edb0cf6 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -135,7 +135,6 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { dateRangeEnd={dateRangeEnd} filters={filters} statusFilter={statusFilter} - sharedProps={sharedProps} /> ('GET_PING_HISTOGRAM'); +export const getPingHistogramSuccess = createAction('GET_PING_HISTOGRAM_SUCCESS'); +export const getPingHistogramFail = createAction('GET_PING_HISTOGRAM_FAIL'); diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index.ts b/x-pack/legacy/plugins/uptime/public/state/api/index.ts index 1d0cac5f878543..be79317dc97c2a 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/api/index.ts @@ -8,3 +8,4 @@ export * from './monitor'; export * from './overview_filters'; export * from './snapshot'; export * from './monitor_status'; +export * from './ping'; diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts b/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts index 8b1220830f091b..80fd311c3ec7e8 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts +++ b/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ThrowReporter } from 'io-ts/lib/ThrowReporter'; +import { PathReporter } from 'io-ts/lib/PathReporter'; import { getApiPath } from '../../lib/helper'; import { BaseParams } from './types'; import { @@ -41,7 +41,7 @@ export const fetchMonitorDetails = async ({ throw new Error(response.statusText); } return response.json().then(data => { - ThrowReporter.report(MonitorDetailsType.decode(data)); + PathReporter.report(MonitorDetailsType.decode(data)); return data; }); }; @@ -68,7 +68,7 @@ export const fetchMonitorLocations = async ({ throw new Error(response.statusText); } return response.json().then(data => { - ThrowReporter.report(MonitorLocationsType.decode(data)); + PathReporter.report(MonitorLocationsType.decode(data)); return data; }); }; diff --git a/x-pack/legacy/plugins/uptime/public/state/api/ping.ts b/x-pack/legacy/plugins/uptime/public/state/api/ping.ts new file mode 100644 index 00000000000000..e0c358fe40e710 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/api/ping.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import qs from 'querystring'; +import { getApiPath } from '../../lib/helper'; +import { APIFn } from './types'; +import { GetPingHistogramParams, HistogramResult } from '../../../common/types'; + +export const fetchPingHistogram: APIFn = async ({ + basePath, + monitorId, + dateStart, + dateEnd, + statusFilter, + filters, +}) => { + const url = getApiPath(`/api/uptime/ping/histogram`, basePath); + const params = { + dateStart, + dateEnd, + ...(monitorId && { monitorId }), + ...(statusFilter && { statusFilter }), + ...(filters && { filters }), + }; + const urlParams = qs.stringify(params).toString(); + const response = await fetch(`${url}?${urlParams}`); + if (!response.ok) { + throw new Error(response.statusText); + } + const responseData = await response.json(); + return responseData; +}; diff --git a/x-pack/legacy/plugins/uptime/public/state/api/types.ts b/x-pack/legacy/plugins/uptime/public/state/api/types.ts index 278cfce29986f0..c88e111d778d53 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/types.ts +++ b/x-pack/legacy/plugins/uptime/public/state/api/types.ts @@ -12,3 +12,5 @@ export interface BaseParams { statusFilter?: string; location?: string; } + +export type APIFn = (params: { basePath: string } & P) => Promise; diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts index 41dda145edb4e2..21d4f7a66ad67d 100644 --- a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts @@ -9,10 +9,12 @@ import { fetchMonitorDetailsEffect } from './monitor'; import { fetchOverviewFiltersEffect } from './overview_filters'; import { fetchSnapshotCountEffect } from './snapshot'; import { fetchMonitorStatusEffect } from './monitor_status'; +import { fetchPingHistogramEffect } from './ping'; export function* rootEffect() { yield fork(fetchMonitorDetailsEffect); yield fork(fetchSnapshotCountEffect); yield fork(fetchOverviewFiltersEffect); yield fork(fetchMonitorStatusEffect); + yield fork(fetchPingHistogramEffect); } diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/ping.ts b/x-pack/legacy/plugins/uptime/public/state/effects/ping.ts new file mode 100644 index 00000000000000..acb9b31915fa99 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/effects/ping.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { takeLatest } from 'redux-saga/effects'; +import { getPingHistogram, getPingHistogramSuccess, getPingHistogramFail } from '../actions'; +import { fetchPingHistogram } from '../api'; +import { fetchEffectFactory } from './fetch_effect'; + +export function* fetchPingHistogramEffect() { + yield takeLatest( + String(getPingHistogram), + fetchEffectFactory(fetchPingHistogram, getPingHistogramSuccess, getPingHistogramFail) + ); +} diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts index 5f915d970e5431..c80ada4f63182f 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts @@ -10,6 +10,7 @@ import { overviewFiltersReducer } from './overview_filters'; import { snapshotReducer } from './snapshot'; import { uiReducer } from './ui'; import { monitorStatusReducer } from './monitor_status'; +import { pingReducer } from './ping'; export const rootReducer = combineReducers({ monitor: monitorReducer, @@ -17,4 +18,5 @@ export const rootReducer = combineReducers({ snapshot: snapshotReducer, ui: uiReducer, monitorStatus: monitorStatusReducer, + ping: pingReducer, }); diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts new file mode 100644 index 00000000000000..76775e6a0a3550 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { handleActions, Action } from 'redux-actions'; +import { getPingHistogram, getPingHistogramSuccess, getPingHistogramFail } from '../actions'; +import { HistogramResult } from '../../../common/types'; + +export interface PingState { + pingHistogram: HistogramResult | null; + errors: any[]; + loading: boolean; +} + +const initialState: PingState = { + pingHistogram: null, + loading: false, + errors: [], +}; + +type MonitorStatusPayload = HistogramResult & Error; + +export const pingReducer = handleActions( + { + [String(getPingHistogram)]: state => ({ + ...state, + loading: true, + }), + + [String(getPingHistogramSuccess)]: (state: PingState, action: Action) => ({ + ...state, + loading: false, + pingHistogram: { ...action.payload }, + }), + + [String(getPingHistogramFail)]: (state, action: Action) => ({ + ...state, + errors: [...state.errors, action.payload], + loading: false, + }), + }, + initialState +); diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts index 38fb3edea4768a..5e3bf95d812922 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts @@ -45,6 +45,11 @@ describe('state selectors', () => { monitor: null, loading: false, }, + ping: { + pingHistogram: null, + loading: false, + errors: [], + }, }; it('selects base path from state', () => { diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts index 337e99f6ede16a..0066241dcc2175 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts @@ -28,3 +28,7 @@ export const selectSelectedMonitor = (state: AppState) => { export const selectMonitorStatus = (state: AppState) => { return state.monitorStatus.status; }; + +export const selectPingHistogram = ({ ping, ui }: AppState) => { + return { data: ping.pingHistogram, loading: ping.loading, lastRefresh: ui.lastRefresh }; +}; diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts b/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts index 897d67dde807ec..cc5744eac6ea11 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts @@ -4,19 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UMGqlRange } from '../../../common/domain_types'; import { UMResolver } from '../../../common/graphql/resolver_types'; -import { - GetFilterBarQueryArgs, - GetMonitorChartsDataQueryArgs, - MonitorChart, - GetSnapshotHistogramQueryArgs, -} from '../../../common/graphql/types'; +import { GetMonitorChartsDataQueryArgs, MonitorChart } from '../../../common/graphql/types'; import { UMServerLibs } from '../../lib/lib'; import { CreateUMGraphQLResolvers, UMContext } from '../types'; -import { HistogramResult } from '../../../common/domain_types'; - -export type UMMonitorsResolver = UMResolver, any, UMGqlRange, UMContext>; export type UMGetMonitorChartsResolver = UMResolver< any | Promise, @@ -25,49 +16,20 @@ export type UMGetMonitorChartsResolver = UMResolver< UMContext >; -export type UMGetFilterBarResolver = UMResolver< - any | Promise, - any, - GetFilterBarQueryArgs, - UMContext ->; - -export type UMGetSnapshotHistogram = UMResolver< - HistogramResult | Promise, - any, - GetSnapshotHistogramQueryArgs, - UMContext ->; - export const createMonitorsResolvers: CreateUMGraphQLResolvers = ( libs: UMServerLibs ): { Query: { - getSnapshotHistogram: UMGetSnapshotHistogram; getMonitorChartsData: UMGetMonitorChartsResolver; }; } => ({ Query: { - async getSnapshotHistogram( - _resolver, - { dateRangeStart, dateRangeEnd, filters, monitorId, statusFilter }, - { APICaller } - ): Promise { - return await libs.pings.getPingHistogram({ - callES: APICaller, - dateRangeStart, - dateRangeEnd, - filters, - monitorId, - statusFilter, - }); - }, async getMonitorChartsData( _resolver, { monitorId, dateRangeStart, dateRangeEnd, location }, { APICaller } ): Promise { - return await libs.monitors.getMonitorChartsData({ + return libs.monitors.getMonitorChartsData({ callES: APICaller, monitorId, dateRangeStart, diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts b/x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts index 8a86d97b4cd8e5..6b8a896c4c60be 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts @@ -7,19 +7,6 @@ import gql from 'graphql-tag'; export const monitorsSchema = gql` - type HistogramDataPoint { - upCount: Int - downCount: Int - x: UnsignedInteger - x0: UnsignedInteger - y: UnsignedInteger - } - - type DataPoint { - x: UnsignedInteger - y: Float - } - "Represents a bucket of monitor status information." type StatusData { "The timeseries point for this status data." @@ -93,11 +80,6 @@ export const monitorsSchema = gql` monitors: [LatestMonitor!] } - type HistogramResult { - histogram: [HistogramDataPoint]! - interval: UnsignedInteger! - } - extend type Query { getMonitors( dateRangeStart: String! @@ -106,14 +88,6 @@ export const monitorsSchema = gql` statusFilter: String ): LatestMonitorsResult - getSnapshotHistogram( - dateRangeStart: String! - dateRangeEnd: String! - filters: String - statusFilter: String - monitorId: String - ): HistogramResult - getMonitorChartsData( monitorId: String! dateRangeStart: String! diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap index b73595d539e933..1b31f44557df04 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap @@ -22,7 +22,7 @@ Object { "y": 1, }, ], - "interval": 36000, + "interval": "1m", } `; @@ -48,7 +48,7 @@ Object { "y": 1, }, ], - "interval": 5609564928000, + "interval": "1h", } `; @@ -68,7 +68,7 @@ Object { "y": 1, }, ], - "interval": 5609564928000, + "interval": "1d", } `; @@ -88,7 +88,7 @@ Object { "y": 1, }, ], - "interval": 5609564928000, + "interval": "1s", } `; @@ -102,7 +102,7 @@ Object { "y": 1, }, ], - "interval": 36000, + "interval": "10s", } `; @@ -122,6 +122,6 @@ Object { "y": 1, }, ], - "interval": 36000, + "interval": "1m", } `; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts index e1e39ac9b26377..866ab110928b49 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts @@ -5,8 +5,7 @@ */ import { set } from 'lodash'; -import { elasticsearchPingsAdapter as adapter } from '../elasticsearch_pings_adapter'; -import { assertCloseTo } from '../../../helper'; +import { elasticsearchPingsAdapter as adapter } from '../es_pings'; describe('ElasticsearchPingsAdapter class', () => { let mockHits: any[]; @@ -35,6 +34,7 @@ describe('ElasticsearchPingsAdapter class', () => { }, }, ], + interval: '1s', }, }, }; @@ -98,12 +98,11 @@ describe('ElasticsearchPingsAdapter class', () => { }); const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: 'now-15m', - dateRangeEnd: 'now', - filters: null, + dateStart: 'now-15m', + dateEnd: 'now', + filters: '', }); - assertCloseTo(result.interval, 36000, 100); - result.interval = 36000; + result.interval = '10s'; expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); @@ -116,12 +115,11 @@ describe('ElasticsearchPingsAdapter class', () => { const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: 'now-15m', - dateRangeEnd: 'now', - filters: null, + dateStart: 'now-15m', + dateEnd: 'now', + filters: '', }); - assertCloseTo(result.interval, 36000, 100); - result.interval = 36000; + result.interval = '1m'; expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); @@ -175,14 +173,13 @@ describe('ElasticsearchPingsAdapter class', () => { }; const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: '1234', - dateRangeEnd: '5678', + dateStart: '1234', + dateEnd: '5678', filters: JSON.stringify(searchFilter), monitorId: undefined, statusFilter: 'down', }); - assertCloseTo(result.interval, 5609564928000, 1000); - result.interval = 5609564928000; + result.interval = '1h'; expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); @@ -229,13 +226,12 @@ describe('ElasticsearchPingsAdapter class', () => { const filters = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: 'now-15m', - dateRangeEnd: 'now', + dateStart: 'now-15m', + dateEnd: 'now', filters, }); - assertCloseTo(result.interval, 36000, 100); - result.interval = 36000; + result.interval = '1m'; expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); @@ -246,14 +242,14 @@ describe('ElasticsearchPingsAdapter class', () => { mockEsClient.mockReturnValue(standardMockResponse); const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: '1234', - dateRangeEnd: '5678', + dateStart: '1234', + dateEnd: '5678', filters: '', monitorId: undefined, statusFilter: 'down', }); - assertCloseTo(result.interval, 5609564928000, 1000); - result.interval = 5609564928000; + + result.interval = '1d'; expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); @@ -267,8 +263,8 @@ describe('ElasticsearchPingsAdapter class', () => { const result = await adapter.getPingHistogram({ callES: mockEsClient, - dateRangeStart: '1234', - dateRangeEnd: '5678', + dateStart: '1234', + dateEnd: '5678', filters: '', monitorId: undefined, statusFilter: 'up', diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_get_ping_historgram.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_get_ping_historgram.ts new file mode 100644 index 00000000000000..66cae497eb0816 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_get_ping_historgram.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get } from 'lodash'; +import { INDEX_NAMES, QUERY } from '../../../../common/constants'; +import { parseFilterQuery, getFilterClause } from '../../helper'; +import { UMElasticsearchQueryFn } from '../framework'; +import { GetPingHistogramParams, HistogramResult } from '../../../../common/types'; +import { HistogramQueryResult } from './types'; + +export const esGetPingHistogram: UMElasticsearchQueryFn< + GetPingHistogramParams, + HistogramResult +> = async ({ callES, dateStart, dateEnd, filters, monitorId, statusFilter }) => { + const boolFilters = parseFilterQuery(filters); + const additionalFilters = []; + if (monitorId) { + additionalFilters.push({ match: { 'monitor.id': monitorId } }); + } + if (boolFilters) { + additionalFilters.push(boolFilters); + } + const filter = getFilterClause(dateStart, dateEnd, additionalFilters); + + const params = { + index: INDEX_NAMES.HEARTBEAT, + body: { + query: { + bool: { + filter, + }, + }, + size: 0, + aggs: { + timeseries: { + auto_date_histogram: { + field: '@timestamp', + buckets: QUERY.DEFAULT_BUCKET_COUNT, + }, + aggs: { + down: { + filter: { + term: { + 'monitor.status': 'down', + }, + }, + }, + up: { + filter: { + term: { + 'monitor.status': 'up', + }, + }, + }, + }, + }, + }, + }, + }; + + const result = await callES('search', params); + const interval = result.aggregations.timeseries?.interval; + const buckets: HistogramQueryResult[] = get(result, 'aggregations.timeseries.buckets', []); + const histogram = buckets.map(bucket => { + const x: number = get(bucket, 'key'); + const downCount: number = get(bucket, 'down.doc_count'); + const upCount: number = get(bucket, 'up.doc_count'); + return { + x, + downCount: statusFilter && statusFilter !== 'down' ? 0 : downCount, + upCount: statusFilter && statusFilter !== 'up' ? 0 : upCount, + y: 1, + }; + }); + return { + histogram, + interval, + }; +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_pings.ts similarity index 67% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts rename to x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_pings.ts index adabffcb1ea4a8..93e3a1bd9397bb 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/es_pings.ts @@ -7,9 +7,8 @@ import { get } from 'lodash'; import { INDEX_NAMES } from '../../../../common/constants'; import { HttpBody, Ping, PingResults } from '../../../../common/graphql/types'; -import { parseFilterQuery, getFilterClause, getHistogramIntervalFormatted } from '../../helper'; -import { UMPingsAdapter, HistogramQueryResult } from './adapter_types'; -import { getHistogramInterval } from '../../helper/get_histogram_interval'; +import { UMPingsAdapter } from './types'; +import { esGetPingHistogram } from './es_get_ping_historgram'; export const elasticsearchPingsAdapter: UMPingsAdapter = { getAll: async ({ @@ -174,80 +173,7 @@ export const elasticsearchPingsAdapter: UMPingsAdapter = { return result.hits.hits[0]?._source; }, - getPingHistogram: async ({ - callES, - dateRangeStart, - dateRangeEnd, - filters, - monitorId, - statusFilter, - }) => { - const boolFilters = parseFilterQuery(filters); - const additionalFilters = []; - if (monitorId) { - additionalFilters.push({ match: { 'monitor.id': monitorId } }); - } - if (boolFilters) { - additionalFilters.push(boolFilters); - } - const filter = getFilterClause(dateRangeStart, dateRangeEnd, additionalFilters); - const interval = getHistogramInterval(dateRangeStart, dateRangeEnd); - const intervalFormatted = getHistogramIntervalFormatted(dateRangeStart, dateRangeEnd); - - const params = { - index: INDEX_NAMES.HEARTBEAT, - body: { - query: { - bool: { - filter, - }, - }, - size: 0, - aggs: { - timeseries: { - date_histogram: { - field: '@timestamp', - fixed_interval: intervalFormatted, - }, - aggs: { - down: { - filter: { - term: { - 'monitor.status': 'down', - }, - }, - }, - up: { - filter: { - term: { - 'monitor.status': 'up', - }, - }, - }, - }, - }, - }, - }, - }; - - const result = await callES('search', params); - const buckets: HistogramQueryResult[] = get(result, 'aggregations.timeseries.buckets', []); - const histogram = buckets.map(bucket => { - const x: number = get(bucket, 'key'); - const downCount: number = get(bucket, 'down.doc_count'); - const upCount: number = get(bucket, 'up.doc_count'); - return { - x, - downCount: statusFilter && statusFilter !== 'down' ? 0 : downCount, - upCount: statusFilter && statusFilter !== 'up' ? 0 : upCount, - y: 1, - }; - }); - return { - histogram, - interval, - }; - }, + getPingHistogram: esGetPingHistogram, getDocCount: async ({ callES }) => { const { count } = await callES('count', { index: INDEX_NAMES.HEARTBEAT }); diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts index 6d93785e01527b..37324a8f521f68 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './adapter_types'; -export { elasticsearchPingsAdapter } from './elasticsearch_pings_adapter'; +export * from './types'; +export { elasticsearchPingsAdapter } from './es_pings'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/types.ts similarity index 79% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts rename to x-pack/legacy/plugins/uptime/server/lib/adapters/pings/types.ts index 8b2a49c0c9ffec..b1b1589af2ca7b 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/types.ts @@ -5,8 +5,8 @@ */ import { DocCount, Ping, PingResults } from '../../../../common/graphql/types'; -import { HistogramResult } from '../../../../common/domain_types'; import { UMElasticsearchQueryFn } from '../framework'; +import { GetPingHistogramParams, HistogramResult } from '../../../../common/types'; export interface GetAllParams { /** @member dateRangeStart timestamp bounds */ @@ -42,19 +42,6 @@ export interface GetLatestMonitorDocsParams { monitorId?: string | null; } -export interface GetPingHistogramParams { - /** @member dateRangeStart timestamp bounds */ - dateRangeStart: string; - /** @member dateRangeEnd timestamp bounds */ - dateRangeEnd: string; - /** @member filters user-defined filters */ - filters?: string | null; - /** @member monitorId optional limit to monitorId */ - monitorId?: string | null; - /** @member statusFilter special filter targeting the latest status of each monitor */ - statusFilter?: string | null; -} - /** * Count the number of documents in heartbeat indices */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts b/x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts index 13b6f3688809c5..45b76ba25470b9 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts @@ -8,4 +8,9 @@ export const assertCloseTo = (actual: number, expected: number, precision: numbe if (Math.abs(expected - actual) > precision) { throw new Error(`expected [${expected}] to be within ${precision} of ${actual}`); } + + // if actual is undefined above math condition will be NAN and it will be always false + if (actual === undefined) { + throw new Error(`expected close to [${expected}] but got [${actual}]`); + } }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts b/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts index f9a8de81332d50..eae8023b66ff4b 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts @@ -5,7 +5,6 @@ */ export { getFilterClause } from './get_filter_clause'; -export { getHistogramInterval } from './get_histogram_interval'; export { getHistogramIntervalFormatted } from './get_histogram_interval_formatted'; export { parseFilterQuery } from './parse_filter_query'; export { assertCloseTo } from './assert_close_to'; diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index.ts b/x-pack/legacy/plugins/uptime/server/rest_api/index.ts index e64b317e67f988..91936b499d8e62 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/index.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/index.ts @@ -16,6 +16,7 @@ import { createGetMonitorLocationsRoute, createGetStatusBarRoute, } from './monitors'; +import { createGetPingHistogramRoute } from './pings/get_ping_histogram'; export * from './types'; export { createRouteWithAuth } from './create_route_with_auth'; @@ -31,4 +32,5 @@ export const restApiRoutes: UMRestApiRouteFactory[] = [ createGetSnapshotCount, createLogMonitorPageRoute, createLogOverviewPageRoute, + createGetPingHistogramRoute, ]; diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts b/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts new file mode 100644 index 00000000000000..c8eb2a1e40ad44 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { UMServerLibs } from '../../lib/lib'; +import { UMRestApiRouteFactory } from '../types'; + +export const createGetPingHistogramRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ + method: 'GET', + path: '/api/uptime/ping/histogram', + validate: { + query: schema.object({ + dateStart: schema.string(), + dateEnd: schema.string(), + monitorId: schema.maybe(schema.string()), + statusFilter: schema.maybe(schema.string()), + filters: schema.maybe(schema.string()), + }), + }, + options: { + tags: ['access:uptime'], + }, + handler: async ({ callES }, _context, request, response): Promise => { + const { dateStart, dateEnd, statusFilter, monitorId, filters } = request.query; + + const result = await libs.pings.getPingHistogram({ + callES, + dateStart, + dateEnd, + monitorId, + statusFilter, + filters, + }); + + return response.ok({ + body: { + ...result, + }, + }); + }, +}); diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram.json deleted file mode 100644 index cf88ccae9cb99b..00000000000000 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "queryResult": { - "histogram": [ - { - "upCount": 93, - "downCount": 7, - "x": 1568172657286, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172680087, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172702888, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172725689, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172748490, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172771291, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568172794092, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172816893, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172839694, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172862495, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172885296, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172908097, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172930898, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172953699, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568172976500, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172999301, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173022102, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173044903, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173067704, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173090505, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173113306, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173136107, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568173158908, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173181709, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173204510, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173227311, - "x0": null, - "y": 1 - } - ] - } -} \ No newline at end of file diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_filter.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_filter.json deleted file mode 100644 index 383d4acd963402..00000000000000 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_filter.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "queryResult": { - "histogram": [ - { - "upCount": 93, - "downCount": 0, - "x": 1568172657286, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172680087, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172702888, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172725689, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172748490, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172771291, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 0, - "x": 1568172794092, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172816893, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172839694, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172862495, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172885296, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172908097, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172930898, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568172953699, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 0, - "x": 1568172976500, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172999301, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173022102, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173044903, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173067704, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173090505, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173113306, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173136107, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 0, - "x": 1568173158908, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173181709, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173204510, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 0, - "x": 1568173227311, - "x0": null, - "y": 1 - } - ] - } -} \ No newline at end of file diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_id.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_id.json deleted file mode 100644 index cf88ccae9cb99b..00000000000000 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_histogram_by_id.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "queryResult": { - "histogram": [ - { - "upCount": 93, - "downCount": 7, - "x": 1568172657286, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172680087, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172702888, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172725689, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172748490, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172771291, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568172794092, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172816893, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172839694, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172862495, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172885296, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172908097, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172930898, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568172953699, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568172976500, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568172999301, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173022102, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173044903, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173067704, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173090505, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173113306, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173136107, - "x0": null, - "y": 1 - }, - { - "upCount": 92, - "downCount": 8, - "x": 1568173158908, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173181709, - "x0": null, - "y": 1 - }, - { - "upCount": 0, - "downCount": 0, - "x": 1568173204510, - "x0": null, - "y": 1 - }, - { - "upCount": 93, - "downCount": 7, - "x": 1568173227311, - "x0": null, - "y": 1 - } - ] - } -} \ No newline at end of file diff --git a/x-pack/test/api_integration/apis/uptime/graphql/index.js b/x-pack/test/api_integration/apis/uptime/graphql/index.js index 64999761fde4ec..54284377ec4308 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/index.js +++ b/x-pack/test/api_integration/apis/uptime/graphql/index.js @@ -14,6 +14,5 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./monitor_charts')); loadTestFile(require.resolve('./monitor_states')); loadTestFile(require.resolve('./ping_list')); - loadTestFile(require.resolve('./snapshot_histogram')); }); } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/snapshot_histogram.ts b/x-pack/test/api_integration/apis/uptime/graphql/snapshot_histogram.ts deleted file mode 100644 index 02fd3fd630d4b2..00000000000000 --- a/x-pack/test/api_integration/apis/uptime/graphql/snapshot_histogram.ts +++ /dev/null @@ -1,88 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { snapshotHistogramQueryString } from '../../../../../legacy/plugins/uptime/public/queries/snapshot_histogram_query'; -import { expectFixtureEql } from './helpers/expect_fixture_eql'; -import { FtrProviderContext } from '../../../ftr_provider_context'; -import { assertCloseTo } from '../../../../../legacy/plugins/uptime/server/lib/helper'; - -export default function({ getService }: FtrProviderContext) { - describe('snapshotHistogram', () => { - before('load heartbeat data', () => getService('esArchiver').load('uptime/full_heartbeat')); - after('unload heartbeat index', () => getService('esArchiver').unload('uptime/full_heartbeat')); - - const supertest = getService('supertest'); - - it('will fetch histogram data for all monitors', async () => { - const getSnapshotHistogramQuery = { - operationName: 'SnapshotHistogram', - query: snapshotHistogramQueryString, - variables: { - dateRangeStart: '2019-09-11T03:31:04.380Z', - dateRangeEnd: '2019-09-11T03:40:34.410Z', - }, - }; - - const { - body: { data }, - } = await supertest - .post('/api/uptime/graphql') - .set('kbn-xsrf', 'foo') - .send({ ...getSnapshotHistogramQuery }); - // manually testing this value and then removing it to avoid flakiness - const { interval } = data.queryResult; - assertCloseTo(interval, 22801, 100); - delete data.queryResult.interval; - expectFixtureEql(data, 'snapshot_histogram'); - }); - - it('will fetch histogram data for a given monitor id', async () => { - const getSnapshotHistogramQuery = { - operationName: 'SnapshotHistogram', - query: snapshotHistogramQueryString, - variables: { - dateRangeStart: '2019-09-11T03:31:04.380Z', - dateRangeEnd: '2019-09-11T03:40:34.410Z', - }, - }; - - const { - body: { data }, - } = await supertest - .post('/api/uptime/graphql') - .set('kbn-xsrf', 'foo') - .send({ ...getSnapshotHistogramQuery }); - const { interval } = data.queryResult; - assertCloseTo(interval, 22801, 100); - delete data.queryResult.interval; - expectFixtureEql(data, 'snapshot_histogram_by_id'); - }); - - it('will fetch histogram data for a given filter', async () => { - const getSnapshotHistogramQuery = { - operationName: 'SnapshotHistogram', - query: snapshotHistogramQueryString, - variables: { - dateRangeStart: '2019-09-11T03:31:04.380Z', - dateRangeEnd: '2019-09-11T03:40:34.410Z', - filters: - '{"bool":{"must":[{"match":{"monitor.status":{"query":"up","operator":"and"}}}]}}', - }, - }; - - const { - body: { data }, - } = await supertest - .post('/api/uptime/graphql') - .set('kbn-xsrf', 'foo') - .send({ ...getSnapshotHistogramQuery }); - const { interval } = data.queryResult; - assertCloseTo(interval, 22801, 100); - delete data.queryResult.interval; - expectFixtureEql(data, 'snapshot_histogram_by_filter'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram.json b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram.json new file mode 100644 index 00000000000000..972d1fd51760c5 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram.json @@ -0,0 +1,24 @@ +{ + "histogram": [ + { "x": 1568172664000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172694000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172724000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172754000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172784000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172814000, "downCount": 8, "upCount": 92, "y": 1 }, + { "x": 1568172844000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172874000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172904000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172934000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172964000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568172994000, "downCount": 8, "upCount": 92, "y": 1 }, + { "x": 1568173024000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173054000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173084000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173114000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173144000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173174000, "downCount": 8, "upCount": 92, "y": 1 }, + { "x": 1568173204000, "downCount": 7, "upCount": 93, "y": 1 }, + { "x": 1568173234000, "downCount": 7, "upCount": 93, "y": 1 } + ] +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_filter.json b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_filter.json new file mode 100644 index 00000000000000..72b2d5276e0254 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_filter.json @@ -0,0 +1,24 @@ +{ + "histogram": [ + { "x": 1568172664000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172694000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172724000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172754000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172784000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172814000, "downCount": 0, "upCount": 92, "y": 1 }, + { "x": 1568172844000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172874000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172904000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172934000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172964000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568172994000, "downCount": 0, "upCount": 92, "y": 1 }, + { "x": 1568173024000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173054000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173084000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173114000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173144000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173174000, "downCount": 0, "upCount": 92, "y": 1 }, + { "x": 1568173204000, "downCount": 0, "upCount": 93, "y": 1 }, + { "x": 1568173234000, "downCount": 0, "upCount": 93, "y": 1 } + ] +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_id.json b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_id.json new file mode 100644 index 00000000000000..8e184b247ab52c --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/fixtures/ping_histogram_by_id.json @@ -0,0 +1,24 @@ +{ + "histogram": [ + { "x": 1568172664000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172694000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172724000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172754000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172784000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172814000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172844000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172874000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172904000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172934000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172964000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568172994000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173024000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173054000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173084000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173114000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173144000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173174000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173204000, "downCount": 0, "upCount": 1, "y": 1 }, + { "x": 1568173234000, "downCount": 0, "upCount": 1, "y": 1 } + ] +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/index.ts b/x-pack/test/api_integration/apis/uptime/rest/index.ts index a86411f7c49ece..30c301c5ecb17b 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/index.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/index.ts @@ -19,6 +19,7 @@ export default function({ getService, loadTestFile }: FtrProviderContext) { after('unload', () => esArchiver.unload('uptime/full_heartbeat')); loadTestFile(require.resolve('./monitor_latest_status')); loadTestFile(require.resolve('./selected_monitor')); + loadTestFile(require.resolve('./ping_histogram')); }); }); } diff --git a/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts new file mode 100644 index 00000000000000..429f50ec0aa5bf --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { expectFixtureEql } from '../graphql/helpers/expect_fixture_eql'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { assertCloseTo } from '../../../../../legacy/plugins/uptime/server/lib/helper'; + +export default function({ getService }: FtrProviderContext) { + describe('pingHistogram', () => { + const supertest = getService('supertest'); + + it('will fetch histogram data for all monitors', async () => { + const dateStart = '2019-09-11T03:31:04.380Z'; + const dateEnd = '2019-09-11T03:40:34.410Z'; + + const apiResponse = await supertest.get( + `/api/uptime/ping/histogram?dateStart=${dateStart}&dateEnd=${dateEnd}` + ); + const data = apiResponse.body; + + // manually testing this value and then removing it to avoid flakiness + const { interval } = data; + assertCloseTo(interval, 22801, 100); + delete data.interval; + expectFixtureEql(data, 'ping_histogram'); + }); + + it('will fetch histogram data for a given monitor id', async () => { + const dateStart = '2019-09-11T03:31:04.380Z'; + const dateEnd = '2019-09-11T03:40:34.410Z'; + const monitorId = '0002-up'; + + const apiResponse = await supertest.get( + `/api/uptime/ping/histogram?monitorId=${monitorId}&dateStart=${dateStart}&dateEnd=${dateEnd}` + ); + const data = apiResponse.body; + + const { interval } = data; + assertCloseTo(interval, 22801, 100); + delete data.interval; + expectFixtureEql(data, 'ping_histogram_by_id'); + }); + + it('will fetch histogram data for a given filter', async () => { + const dateStart = '2019-09-11T03:31:04.380Z'; + const dateEnd = '2019-09-11T03:40:34.410Z'; + const filters = + '{"bool":{"must":[{"match":{"monitor.status":{"query":"up","operator":"and"}}}]}}'; + + const apiResponse = await supertest.get( + `/api/uptime/ping/histogram?dateStart=${dateStart}&dateEnd=${dateEnd}&filters=${filters}` + ); + const data = apiResponse.body; + + const { interval } = data; + assertCloseTo(interval, 22801, 100); + delete data.interval; + expectFixtureEql(data, 'ping_histogram_by_filter'); + }); + }); +} From 0d03ade9eafc5862bdc6da0a800862a2d7ad9656 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 30 Jan 2020 09:25:47 +0100 Subject: [PATCH 05/69] NP Migration: Rollup plugin (#53503) * Start shimming rollup plugin * continued shimming rollup ui * Remove unnecessarily return * Register management section * Replace ui/chrome * Replace ui/documentation_links * Replace ui/kfetch and ui/courier * Start shimming rollup plugin * continued shimming rollup ui * Remove unnecessarily return * Register management section * Replace ui/chrome * Replace ui/documentation_links * Replace ui/kfetch and ui/courier * Replace ui/notify * Move ui/ imports to legacy_imports.ts * Update NP mock for management * Refactoring * Read body from error object * Update setup_environment.js * Update unit tests * Get rid of injectI18n * Replace npStart and npSetup usage to services * Import search strategy stuff from the top level of the data plugin * Update unit tests * Do not prepend the url * Fix merge conflicts * Refactoring * Revert removal of setUserHasLeftApp * Export getSearchErrorType * Remove extra wrapper - Router * Fix cause prop. * Leave just static imports in legacy_imports.js * Add TS * Pass statusCode instead of statusText * Move template in a separate file * Move app register to setup * Add karma mock for management setup * Add EditorConfigProviderRegistry export Co-authored-by: Maryia Lapata Co-authored-by: Elastic Machine --- .../ui/public/agg_types/filter/index.ts | 2 +- .../agg_types/param_types/filter/index.ts | 2 +- .../new_platform/new_platform.karma_mock.js | 12 ++ .../ui/public/new_platform/new_platform.ts | 3 +- src/legacy/ui/public/vis/config/index.ts | 2 +- src/plugins/data/public/search/index.ts | 2 + .../helpers/http_requests.js | 70 ---------- .../client_integration/helpers/index.js | 4 +- .../helpers/job_clone.helpers.js | 4 +- .../helpers/job_create.helpers.js | 4 +- .../helpers/job_list.helpers.js | 4 +- .../helpers/setup_context.tsx | 23 ++++ .../helpers/setup_environment.js | 23 ---- .../helpers/setup_environment.ts | 44 ++++++ .../job_create_clone.test.js | 17 ++- .../job_create_date_histogram.test.js | 26 ++-- .../job_create_histogram.test.js | 29 ++-- .../job_create_logistics.test.js | 29 ++-- .../job_create_metrics.test.js | 28 ++-- .../job_create_review.test.js | 54 ++++---- .../job_create_terms.test.js | 41 ++++-- .../client_integration/job_list.test.js | 20 +-- .../client_integration/job_list_clone.test.js | 23 ++-- .../rollup/common/{index.js => index.ts} | 0 .../common/{ui_metric.js => ui_metric.ts} | 0 x-pack/legacy/plugins/rollup/index.js | 12 +- .../plugins/rollup/public/application.tsx | 47 +++++++ .../rollup/public/crud_app/_crud_app.scss | 4 - .../plugins/rollup/public/crud_app/index.js | 98 -------------- .../plugins/rollup/public/crud_app/main.html | 3 - .../confirm_delete_modal.js | 57 ++++---- .../sections/job_create/job_create.js | 24 ++-- .../job_create/navigation/navigation.js | 8 +- .../job_create/steps/step_date_histogram.js | 12 +- .../job_create/steps/step_histogram.js | 10 +- .../job_create/steps/step_logistics.js | 14 +- .../sections/job_create/steps/step_metrics.js | 14 +- .../sections/job_create/steps/step_review.js | 6 +- .../sections/job_create/steps/step_terms.js | 10 +- .../steps_config/validate_rollup_index.js | 2 +- .../job_list/detail_panel/detail_panel.js | 12 +- .../detail_panel/detail_panel.test.js | 4 +- .../crud_app/sections/job_list/job_list.js | 23 ++-- .../sections/job_list/job_list.test.js | 35 ++--- .../sections/job_list/job_table/job_table.js | 11 +- .../rollup/public/crud_app/services/api.js | 23 ++-- .../services/{api_errors.js => api_errors.ts} | 22 +-- .../crud_app/services/documentation_links.js | 25 ++-- .../{http_provider.js => http_provider.ts} | 11 +- .../rollup/public/crud_app/services/index.js | 15 +- .../crud_app/store/actions/create_job.js | 20 +-- .../crud_app/store/actions/delete_jobs.js | 7 +- .../{index.js => index.ts} | 12 +- .../public/index_pattern_creation/index.js | 17 --- .../public/index_pattern_creation/register.js | 12 -- .../rollup_index_pattern_creation_config.js | 8 +- .../rollup/public/index_pattern_list/index.js | 16 --- .../public/index_pattern_list/register.js | 12 -- .../plugins/rollup/public/kibana_services.ts | 30 ++++ x-pack/legacy/plugins/rollup/public/legacy.ts | 30 ++++ .../plugins/rollup/public/legacy_imports.ts | 12 ++ x-pack/legacy/plugins/rollup/public/plugin.ts | 128 ++++++++++++++++++ .../plugins/rollup/public/search/index.js | 17 --- .../plugins/rollup/public/search/register.js | 12 -- ..._strategy.js => rollup_search_strategy.ts} | 36 +++-- .../plugins/rollup/public/services/api.js | 14 -- .../public/visualize/agg_type_field_filter.js | 4 +- .../public/visualize/agg_type_filter.js | 4 +- .../rollup/public/visualize/editor_config.js | 3 +- .../plugins/rollup/public/visualize/index.js | 21 --- 70 files changed, 716 insertions(+), 667 deletions(-) delete mode 100644 x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/http_requests.js create mode 100644 x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx delete mode 100644 x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.js create mode 100644 x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts rename x-pack/legacy/plugins/rollup/common/{index.js => index.ts} (100%) rename x-pack/legacy/plugins/rollup/common/{ui_metric.js => ui_metric.ts} (100%) create mode 100644 x-pack/legacy/plugins/rollup/public/application.tsx delete mode 100644 x-pack/legacy/plugins/rollup/public/crud_app/index.js delete mode 100644 x-pack/legacy/plugins/rollup/public/crud_app/main.html rename x-pack/legacy/plugins/rollup/public/crud_app/services/{api_errors.js => api_errors.ts} (54%) rename x-pack/legacy/plugins/rollup/public/crud_app/services/{http_provider.js => http_provider.ts} (61%) rename x-pack/legacy/plugins/rollup/public/extend_index_management/{index.js => index.ts} (76%) delete mode 100644 x-pack/legacy/plugins/rollup/public/index_pattern_creation/index.js delete mode 100644 x-pack/legacy/plugins/rollup/public/index_pattern_creation/register.js delete mode 100644 x-pack/legacy/plugins/rollup/public/index_pattern_list/index.js delete mode 100644 x-pack/legacy/plugins/rollup/public/index_pattern_list/register.js create mode 100644 x-pack/legacy/plugins/rollup/public/kibana_services.ts create mode 100644 x-pack/legacy/plugins/rollup/public/legacy.ts create mode 100644 x-pack/legacy/plugins/rollup/public/legacy_imports.ts create mode 100644 x-pack/legacy/plugins/rollup/public/plugin.ts delete mode 100644 x-pack/legacy/plugins/rollup/public/search/index.js delete mode 100644 x-pack/legacy/plugins/rollup/public/search/register.js rename x-pack/legacy/plugins/rollup/public/search/{rollup_search_strategy.js => rollup_search_strategy.ts} (74%) delete mode 100644 x-pack/legacy/plugins/rollup/public/services/api.js delete mode 100644 x-pack/legacy/plugins/rollup/public/visualize/index.js diff --git a/src/legacy/ui/public/agg_types/filter/index.ts b/src/legacy/ui/public/agg_types/filter/index.ts index 3fc577e7e9a23a..35d06807d0ec24 100644 --- a/src/legacy/ui/public/agg_types/filter/index.ts +++ b/src/legacy/ui/public/agg_types/filter/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export { aggTypeFilters } from './agg_type_filters'; +export { aggTypeFilters, AggTypeFilters } from './agg_type_filters'; export { propFilter } from './prop_filter'; diff --git a/src/legacy/ui/public/agg_types/param_types/filter/index.ts b/src/legacy/ui/public/agg_types/param_types/filter/index.ts index ce5c7c4f9fea5f..2e0039c96a1921 100644 --- a/src/legacy/ui/public/agg_types/param_types/filter/index.ts +++ b/src/legacy/ui/public/agg_types/param_types/filter/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { aggTypeFieldFilters } from './field_filters'; +export { aggTypeFieldFilters, AggTypeFieldFilters } from './field_filters'; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 31dd00c37069f0..f98b8801d52663 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -147,6 +147,13 @@ export const npSetup = { useChartsTheme: sinon.fake(), }, }, + management: { + sections: { + getSection: () => ({ + registerApp: sinon.fake(), + }), + }, + }, }, }; @@ -167,6 +174,11 @@ export const npStart = { hasItem: sinon.fake(), }), }, + sections: { + getSection: () => ({ + registerApp: sinon.fake(), + }), + }, }, embeddable: { getEmbeddableFactory: sinon.fake(), diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index cb98e72591b039..2ade98ec54efd0 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -32,7 +32,7 @@ import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/publ import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public'; import { HomePublicPluginSetup, HomePublicPluginStart } from '../../../../plugins/home/public'; import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public'; -import { ManagementStart } from '../../../../plugins/management/public'; +import { ManagementSetup, ManagementStart } from '../../../../plugins/management/public'; import { BfetchPublicSetup, BfetchPublicStart } from '../../../../plugins/bfetch/public'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public'; import { @@ -54,6 +54,7 @@ export interface PluginsSetup { kibana_legacy: KibanaLegacySetup; share: SharePluginSetup; usageCollection: UsageCollectionSetup; + management: ManagementSetup; } export interface PluginsStart { diff --git a/src/legacy/ui/public/vis/config/index.ts b/src/legacy/ui/public/vis/config/index.ts index 5e87ac17b98fb3..ee7385518a85d4 100644 --- a/src/legacy/ui/public/vis/config/index.ts +++ b/src/legacy/ui/public/vis/config/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export { editorConfigProviders } from './editor_config_providers'; +export { editorConfigProviders, EditorConfigProviderRegistry } from './editor_config_providers'; export * from './types'; diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index cf7e0268d745a0..9d6e5072d657f2 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -47,6 +47,8 @@ export { hasSearchStategyForIndexPattern, defaultSearchStrategy, SearchError, + SearchStrategyProvider, + getSearchErrorType, } from './search_strategy'; export { diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/http_requests.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/http_requests.js deleted file mode 100644 index 4552e62c371a1e..00000000000000 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/http_requests.js +++ /dev/null @@ -1,70 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import sinon from 'sinon'; - -// Register helpers to mock HTTP Requests -const registerHttpRequestMockHelpers = server => { - const setIndexPatternValidityResponse = response => { - const defaultResponse = { - doesMatchIndices: true, - doesMatchRollupIndices: false, - dateFields: ['foo', 'bar'], - numericFields: [], - keywordFields: [], - }; - server.respondWith(/\/api\/rollup\/index_pattern_validity\/.*/, [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify({ ...defaultResponse, ...response }), - ]); - }; - - const setCreateJobResponse = (responsePayload = {}) => { - server.respondWith(/\/api\/rollup\/create/, [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(responsePayload), - ]); - }; - - const setStartJobResponse = () => { - server.respondWith(/\/api\/rollup\/start/, [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify({}), - ]); - }; - - const setLoadJobsResponse = response => { - server.respondWith('GET', '/api/rollup/jobs', [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(response), - ]); - }; - - return { - setIndexPatternValidityResponse, - setCreateJobResponse, - setLoadJobsResponse, - setStartJobResponse, - }; -}; - -export const init = () => { - const server = sinon.fakeServer.create(); - server.respondImmediately = true; - - // We make requests to APIs which don't impact the UX, e.g. UI metric telemetry, - // and we can mock them all with a 200 instead of mocking each one individually. - server.respondWith([200, {}, '']); - - return { - server, - httpRequestsMockHelpers: registerHttpRequestMockHelpers(server), - }; -}; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js index 9573e2f405b84a..4a5b67e687d852 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js @@ -10,7 +10,9 @@ import { setup as jobCloneSetup } from './job_clone.helpers'; export { nextTick, getRandomString, findTestSubject } from '../../../../../../test_utils'; -export { setupEnvironment } from './setup_environment'; +export { mockHttpRequest } from './setup_environment'; + +export { wrapComponent } from './setup_context'; export const pageHelpers = { jobCreate: { setup: jobCreateSetup }, diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js index db0bb49289b605..a8376bb31b23ff 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js @@ -10,8 +10,10 @@ import { JobCreate } from '../../../public/crud_app/sections'; import { JOB_TO_CLONE } from './constants'; import { deserializeJob } from '../../../public/crud_app/services'; +import { wrapComponent } from './setup_context'; + export const setup = props => { - const initTestBed = registerTestBed(JobCreate, { + const initTestBed = registerTestBed(wrapComponent(JobCreate), { store: createRollupJobsStore({ cloneJob: { job: deserializeJob(JOB_TO_CLONE.jobs[0]) }, }), diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js index 5de5d02dadd837..2395fd014dd1e5 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js @@ -10,7 +10,9 @@ import { JobCreate } from '../../../public/crud_app/sections'; import { JOB_TO_CREATE } from './constants'; -const initTestBed = registerTestBed(JobCreate, { store: rollupJobsStore }); +import { wrapComponent } from './setup_context'; + +const initTestBed = registerTestBed(wrapComponent(JobCreate), { store: rollupJobsStore }); export const setup = props => { const testBed = initTestBed(props); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js index 10fa79f775fdca..bcad8c29c87c03 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js @@ -9,6 +9,8 @@ import { registerRouter } from '../../../public/crud_app/services'; import { createRollupJobsStore } from '../../../public/crud_app/store'; import { JobList } from '../../../public/crud_app/sections/job_list'; +import { wrapComponent } from './setup_context'; + const testBedConfig = { store: createRollupJobsStore, memoryRouter: { @@ -19,4 +21,4 @@ const testBedConfig = { }, }; -export const setup = registerTestBed(JobList, testBedConfig); +export const setup = registerTestBed(wrapComponent(JobList), testBedConfig); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx new file mode 100644 index 00000000000000..4c5a8e17c586ac --- /dev/null +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FunctionComponent } from 'react'; + +import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import { coreMock } from '../../../../../../../src/core/public/mocks'; +const startMock = coreMock.createStart(); + +const services = { + setBreadcrumbs: startMock.chrome.setBreadcrumbs, +}; + +const wrapComponent = (Component: FunctionComponent) => (props: any) => ( + + + +); + +export { wrapComponent }; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.js deleted file mode 100644 index 71e7f050786b5c..00000000000000 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.js +++ /dev/null @@ -1,23 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import axios from 'axios'; -import axiosXhrAdapter from 'axios/lib/adapters/xhr'; - -import { setHttp } from '../../../public/crud_app/services'; -import { init as initHttpRequests } from './http_requests'; - -export const setupEnvironment = () => { - // axios has a $http like interface so using it to simulate $http - setHttp(axios.create({ adapter: axiosXhrAdapter })); - - const { server, httpRequestsMockHelpers } = initHttpRequests(); - - return { - server, - httpRequestsMockHelpers, - }; -}; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts new file mode 100644 index 00000000000000..a8db058908ad49 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +interface RequestMocks { + jobs?: object; + createdJob?: object; + indxPatternVldtResp?: object; + [key: string]: any; +} + +const mockHttpRequest = ( + http: any, + { jobs = {}, createdJob = {}, indxPatternVldtResp = {} }: RequestMocks = {} +) => { + http.get.mockImplementation(async (url: string) => { + if (url === '/api/rollup/jobs') { + return jobs; + } + + if (url.startsWith('/api/rollup/index_pattern_validity')) { + return { + doesMatchIndices: true, + doesMatchRollupIndices: false, + dateFields: ['foo', 'bar'], + numericFields: [], + keywordFields: [], + ...indxPatternVldtResp, + }; + } + + return {}; + }); + + // mock '/api/rollup/start' + http.post.mockImplementation(async (url: string) => ({})); + + // mock '/api/rollup/create + http.put.mockImplementation(async (url: string) => createdJob); +}; + +export { mockHttpRequest }; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js index 4ffffd7574bd81..b7c98ed179c7ab 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; jest.mock('ui/new_platform'); @@ -17,26 +18,28 @@ const { } = JOB_TO_CLONE; describe('Cloning a rollup job through create job wizard', () => { - let httpRequestsMockHelpers; - let server; let find; let exists; let form; let table; let actions; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { - httpRequestsMockHelpers.setIndexPatternValidityResponse(JOB_CLONE_INDEX_PATTERN_CHECK); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK }); ({ exists, find, form, actions, table } = setup()); }); - afterAll(() => { - server.restore(); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); }); it('should have fields correctly pre-populated', async () => { diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js index c4336c535a0ee0..b8ec7d9f85d009 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js @@ -6,7 +6,8 @@ import moment from 'moment-timezone'; -import { setupEnvironment, pageHelpers } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers } from './helpers'; jest.mock('ui/new_platform'); @@ -15,30 +16,31 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 2: Date histogram', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; let goToStep; let form; let getEuiStepsHorizontalActive; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); - - afterAll(() => { - server.restore(); - }); - beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, form, getEuiStepsHorizontalActive, goToStep } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); + }); + describe('layout', () => { beforeEach(async () => { await goToStep(2); @@ -71,7 +73,7 @@ describe('Create Rollup Job, step 2: Date histogram', () => { describe('Date field select', () => { it('should set the options value from the index pattern', async () => { const dateFields = ['field1', 'field2', 'field3']; - httpRequestsMockHelpers.setIndexPatternValidityResponse({ dateFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields } }); await goToStep(2); @@ -83,7 +85,7 @@ describe('Create Rollup Job, step 2: Date histogram', () => { it('should sort the options in ascending order', async () => { const dateFields = ['field3', 'field2', 'field1']; - httpRequestsMockHelpers.setIndexPatternValidityResponse({ dateFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields } }); await goToStep(2); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js index f91c4582ba2479..c4b5d753f1a262 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers } from './helpers'; jest.mock('ui/new_platform'); @@ -13,8 +14,6 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 4: Histogram', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; @@ -22,22 +21,26 @@ describe('Create Rollup Job, step 4: Histogram', () => { let goToStep; let table; let form; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); + }); + const numericFields = ['a-numericField', 'b-numericField']; const goToStepAndOpenFieldChooser = async () => { @@ -108,7 +111,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { describe('when no histogram fields are availalbe', () => { it('should indicate it to the user', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields: [] }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: [] } }); await goToStepAndOpenFieldChooser(); const { tableCellsValues } = table.getMetaData('rollupJobHistogramFieldChooser-table'); @@ -119,7 +122,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { describe('when histogram fields are available', () => { beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); await goToStepAndOpenFieldChooser(); }); @@ -153,7 +156,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { it('should have a delete button on each row to remove an histogram field', async () => { // First let's add a term to the list - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); await goToStepAndOpenFieldChooser(); const { rows: fieldChooserRows } = table.getMetaData('rollupJobHistogramFieldChooser-table'); fieldChooserRows[0].reactWrapper.simulate('click'); @@ -180,7 +183,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { }; beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); await goToStep(4); addHistogramFieldToList(); }); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js index c960eabb37dcb7..98af94437fa5a9 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js @@ -13,7 +13,8 @@ import { YEAR, } from '../../../../../../src/plugins/es_ui_shared/public/components/cron_editor'; import { indexPatterns } from '../../../../../../src/plugins/data/public'; -import { setupEnvironment, pageHelpers } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers } from './helpers'; jest.mock('ui/new_platform'); @@ -22,29 +23,31 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 1: Logistics', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; let form; let getEuiStepsHorizontalActive; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, form, getEuiStepsHorizontalActive } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); + }); + it('should have the horizontal step active on "Logistics"', () => { expect(getEuiStepsHorizontalActive()).toContain('Logistics'); }); @@ -94,14 +97,14 @@ describe('Create Rollup Job, step 1: Logistics', () => { }); it('should not allow an unknown index pattern', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ doesMatchIndices: false }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { doesMatchIndices: false } }); await form.setInputValue('rollupIndexPattern', 'unknown', true); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain("Index pattern doesn't match any indices."); }); it('should not allow an index pattern without time fields', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ dateFields: [] }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields: [] } }); await form.setInputValue('rollupIndexPattern', 'abc', true); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain( @@ -110,7 +113,9 @@ describe('Create Rollup Job, step 1: Logistics', () => { }); it('should not allow an index pattern that matches a rollup index', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ doesMatchRollupIndices: true }); + mockHttpRequest(npStart.core.http, { + indxPatternVldtResp: { doesMatchRollupIndices: true }, + }); await form.setInputValue('rollupIndexPattern', 'abc', true); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain('Index pattern must not match rollup indices.'); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js index bbbd2974c56dbf..a72dc8b25c0839 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers } from './helpers'; jest.mock('ui/new_platform'); @@ -13,8 +14,6 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 5: Metrics', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; @@ -22,22 +21,26 @@ describe('Create Rollup Job, step 5: Metrics', () => { let goToStep; let table; let metrics; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, metrics } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); + }); + const numericFields = ['a-numericField', 'c-numericField']; const dateFields = ['b-dateField', 'd-dateField']; @@ -109,7 +112,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { describe('table', () => { beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, dateFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); await goToStepAndOpenFieldChooser(); }); @@ -166,7 +169,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { describe('when fields are added', () => { beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, dateFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); await goToStepAndOpenFieldChooser(); }); @@ -257,7 +260,8 @@ describe('Create Rollup Job, step 5: Metrics', () => { let getFieldListTableRows; beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, dateFields }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); + await goToStep(5); await addFieldToList('numeric'); await addFieldToList('date'); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js index d7bc5416263fe4..0fa9509368d3f7 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers } from './helpers'; +import { pageHelpers, mockHttpRequest } from './helpers'; import { first } from 'lodash'; +import { setHttp } from '../../public/crud_app/services'; import { JOBS } from './helpers/constants'; jest.mock('ui/new_platform'); @@ -15,8 +16,6 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 6: Review', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; @@ -24,21 +23,25 @@ describe('Create Rollup Job, step 6: Review', () => { let goToStep; let table; let form; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + npStart.core.http.post.mockClear(); + npStart.core.http.put.mockClear(); + }); + describe('layout', () => { beforeEach(async () => { await goToStep(6); @@ -81,7 +84,7 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Terms" & "Request" tab if a term aggregation was added', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields: ['my-field'] }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: ['my-field'] } }); await goToStep(3); selectFirstField('Terms'); @@ -93,7 +96,7 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Histogram" & "Request" tab if a histogram field was added', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields: ['a-field'] }); + mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: ['a-field'] } }); await goToStep(4); selectFirstField('Histogram'); form.setInputValue('rollupJobCreateHistogramInterval', 3); // set an interval @@ -105,9 +108,11 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Metrics" & "Request" tab if a histogram field was added', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ - numericFields: ['a-field'], - dateFields: ['b-field'], + mockHttpRequest(npStart.core.http, { + indxPatternVldtResp: { + numericFields: ['a-field'], + dateFields: ['b-field'], + }, }); await goToStep(5); selectFirstField('Metrics'); @@ -125,27 +130,30 @@ describe('Create Rollup Job, step 6: Review', () => { describe('without starting job after creation', () => { it('should call the "create" Api server endpoint', async () => { - httpRequestsMockHelpers.setCreateJobResponse(first(JOBS.jobs)); + mockHttpRequest(npStart.core.http, { + createdJob: first(JOBS.jobs), + }); await goToStep(6); - expect(server.requests.find(r => r.url === jobCreateApiPath)).toBe(undefined); // make sure it hasn't been called - expect(server.requests.find(r => r.url === jobStartApiPath)).toBe(undefined); // make sure it hasn't been called + expect(npStart.core.http.put).not.toHaveBeenCalledWith(jobCreateApiPath); // make sure it hasn't been called + expect(npStart.core.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); // Given the following anti-jitter sleep x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js // we add a longer sleep here :( await new Promise(res => setTimeout(res, 750)); - expect(server.requests.find(r => r.url === jobCreateApiPath)).not.toBe(undefined); // It has been called! - expect(server.requests.find(r => r.url === jobStartApiPath)).toBe(undefined); // It has still not been called! + expect(npStart.core.http.put).toHaveBeenCalledWith(jobCreateApiPath, expect.anything()); // It has been called! + expect(npStart.core.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // It has still not been called! }); }); describe('with starting job after creation', () => { it('should call the "create" and "start" Api server endpoints', async () => { - httpRequestsMockHelpers.setCreateJobResponse(first(JOBS.jobs)); - httpRequestsMockHelpers.setStartJobResponse(); + mockHttpRequest(npStart.core.http, { + createdJob: first(JOBS.jobs), + }); await goToStep(6); @@ -153,14 +161,14 @@ describe('Create Rollup Job, step 6: Review', () => { target: { checked: true }, }); - expect(server.requests.find(r => r.url === jobStartApiPath)).toBe(undefined); // make sure it hasn't been called + expect(npStart.core.http.post).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); // Given the following anti-jitter sleep x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js // we add a longer sleep here :( await new Promise(res => setTimeout(res, 750)); - expect(server.requests.find(r => r.url === jobStartApiPath)).not.toBe(undefined); // It has been called! + expect(npStart.core.http.post).toHaveBeenCalledWith(jobStartApiPath, expect.anything()); // It has been called! }); }); }); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js index d3a0aaa08e148d..f111a7df2c2501 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers } from './helpers'; +import { setHttp } from '../../public/crud_app/services'; +import { pageHelpers, mockHttpRequest } from './helpers'; jest.mock('ui/new_platform'); @@ -13,30 +14,30 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 3: Terms', () => { - let server; - let httpRequestsMockHelpers; let find; let exists; let actions; let getEuiStepsHorizontalActive; let goToStep; let table; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - httpRequestsMockHelpers.setIndexPatternValidityResponse(); + mockHttpRequest(npStart.core.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table } = setup()); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + }); + const numericFields = ['a-numericField', 'c-numericField']; const keywordFields = ['b-keywordField', 'd-keywordField']; @@ -108,9 +109,11 @@ describe('Create Rollup Job, step 3: Terms', () => { describe('when no terms are available', () => { it('should indicate it to the user', async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ - numericFields: [], - keywordFields: [], + mockHttpRequest(npStart.core.http, { + indxPatternVldtResp: { + numericFields: [], + keywordFields: [], + }, }); await goToStepAndOpenFieldChooser(); @@ -122,7 +125,12 @@ describe('Create Rollup Job, step 3: Terms', () => { describe('when terms are available', () => { beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, keywordFields }); + mockHttpRequest(npStart.core.http, { + indxPatternVldtResp: { + numericFields, + keywordFields, + }, + }); await goToStepAndOpenFieldChooser(); }); @@ -163,7 +171,12 @@ describe('Create Rollup Job, step 3: Terms', () => { it('should have a delete button on each row to remove a term', async () => { // First let's add a term to the list - httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, keywordFields }); + mockHttpRequest(npStart.core.http, { + indxPatternVldtResp: { + numericFields, + keywordFields, + }, + }); await goToStepAndOpenFieldChooser(); const { rows: fieldChooserRows } = table.getMetaData('rollupJobTermsFieldChooser-table'); fieldChooserRows[0].reactWrapper.simulate('click'); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js index 16cb41bc766776..a9e474cf0b5598 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getRouter } from '../../public/crud_app/services'; -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { getRouter, setHttp } from '../../public/crud_app/services'; +import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOBS } from './helpers/constants'; jest.mock('ui/new_platform'); @@ -22,22 +22,18 @@ const { setup } = pageHelpers.jobList; describe('', () => { describe('detail panel', () => { - let server; - let httpRequestsMockHelpers; let component; let table; let exists; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(async () => { - httpRequestsMockHelpers.setLoadJobsResponse(JOBS); + mockHttpRequest(npStart.core.http, { jobs: JOBS }); ({ component, exists, table } = setup()); @@ -45,6 +41,10 @@ describe('', () => { component.update(); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + }); + test('should open the detail panel when clicking on a job in the table', () => { const { rows } = table.getMetaData('rollupJobsListTable'); const button = rows[0].columns[1].reactWrapper.find('button'); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js index 6feabe7f772eef..8a36af83def4c8 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js +++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; import { getRouter } from '../../public/crud_app/services/routing'; +import { setHttp } from '../../public/crud_app/services'; import { CRUD_APP_BASE_PATH } from '../../public/crud_app/constants'; jest.mock('ui/new_platform'); @@ -16,24 +17,22 @@ jest.mock('lodash/function/debounce', () => fn => fn); const { setup } = pageHelpers.jobList; describe('Smoke test cloning an existing rollup job from job list', () => { - let server; - let httpRequestsMockHelpers; let table; let find; let component; let exists; + let npStart; beforeAll(() => { - ({ server, httpRequestsMockHelpers } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); + npStart = require('ui/new_platform').npStart; // eslint-disable-line + setHttp(npStart.core.http); }); beforeEach(async () => { - httpRequestsMockHelpers.setIndexPatternValidityResponse(JOB_CLONE_INDEX_PATTERN_CHECK); - httpRequestsMockHelpers.setLoadJobsResponse(JOB_TO_CLONE); + mockHttpRequest(npStart.core.http, { + jobs: JOB_TO_CLONE, + indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK, + }); ({ find, exists, table, component } = setup()); @@ -41,6 +40,10 @@ describe('Smoke test cloning an existing rollup job from job list', () => { component.update(); }); + afterEach(() => { + npStart.core.http.get.mockClear(); + }); + it('should navigate to create view with default values set', async () => { const router = getRouter(); const { rows } = table.getMetaData('rollupJobsListTable'); diff --git a/x-pack/legacy/plugins/rollup/common/index.js b/x-pack/legacy/plugins/rollup/common/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/common/index.js rename to x-pack/legacy/plugins/rollup/common/index.ts diff --git a/x-pack/legacy/plugins/rollup/common/ui_metric.js b/x-pack/legacy/plugins/rollup/common/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/common/ui_metric.js rename to x-pack/legacy/plugins/rollup/common/ui_metric.ts diff --git a/x-pack/legacy/plugins/rollup/index.js b/x-pack/legacy/plugins/rollup/index.js index f4210435abc09e..a10407b19fa93b 100644 --- a/x-pack/legacy/plugins/rollup/index.js +++ b/x-pack/legacy/plugins/rollup/index.js @@ -26,7 +26,7 @@ export function rollup(kibana) { require: ['kibana', 'elasticsearch', 'xpack_main'], uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), - managementSections: ['plugins/rollup/crud_app'], + managementSections: ['plugins/rollup/legacy'], uiSettingDefaults: { [CONFIG_ROLLUPS]: { name: i18n.translate('xpack.rollupJobs.rollupIndexPatternsTitle', { @@ -41,13 +41,9 @@ export function rollup(kibana) { category: ['rollups'], }, }, - indexManagement: [ - 'plugins/rollup/index_pattern_creation', - 'plugins/rollup/index_pattern_list', - 'plugins/rollup/extend_index_management', - ], - visualize: ['plugins/rollup/visualize'], - search: ['plugins/rollup/search'], + indexManagement: ['plugins/rollup/legacy'], + visualize: ['plugins/rollup/legacy'], + search: ['plugins/rollup/legacy'], }, init: function(server) { const { usageCollection } = server.newPlatform.setup.plugins; diff --git a/x-pack/legacy/plugins/rollup/public/application.tsx b/x-pack/legacy/plugins/rollup/public/application.tsx new file mode 100644 index 00000000000000..df17d37bc34656 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/public/application.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { Provider } from 'react-redux'; +import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { ChromeBreadcrumb, CoreSetup } from '../../../../../src/core/public'; +// @ts-ignore +import { rollupJobsStore } from './crud_app/store'; +// @ts-ignore +import { App } from './crud_app/app'; + +/** + * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle. + */ +export const renderApp = async ( + core: CoreSetup, + { + element, + setBreadcrumbs, + }: { element: HTMLElement; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void } +) => { + const [coreStart] = await core.getStartServices(); + const I18nContext = coreStart.i18n.Context; + + render( + + + + + + + , + element + ); + return () => { + unmountComponentAtNode(element); + }; +}; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss b/x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss index e1166d0942a5cc..9e3bd491115ced 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss +++ b/x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss @@ -5,10 +5,6 @@ align-items: flex-end; /* 1 */ } -.rollupJobsRoot { - display: flex; -} - /** * 1. Ensure panel fills width of parent when search input yields no matching rollup jobs. */ diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/index.js b/x-pack/legacy/plugins/rollup/public/crud_app/index.js deleted file mode 100644 index 82bbb90d2e33cf..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/crud_app/index.js +++ /dev/null @@ -1,98 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { - FeatureCatalogueRegistryProvider, - FeatureCatalogueCategory, -} from 'ui/registry/feature_catalogue'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { Provider } from 'react-redux'; -import { i18n } from '@kbn/i18n'; -import { I18nContext } from 'ui/i18n'; -import { management } from 'ui/management'; -import routes from 'ui/routes'; - -import { CRUD_APP_BASE_PATH } from './constants'; -import { setHttp, setUserHasLeftApp } from './services'; -import { App } from './app'; -import template from './main.html'; -import { rollupJobsStore } from './store'; - -const esSection = management.getSection('elasticsearch'); - -esSection.register('rollup_jobs', { - visible: true, - display: i18n.translate('xpack.rollupJobs.appTitle', { defaultMessage: 'Rollup Jobs' }), - order: 3, - url: `#${CRUD_APP_BASE_PATH}/job_list`, -}); - -const renderReact = async elem => { - render( - - - - - , - elem - ); -}; - -routes.when(`${CRUD_APP_BASE_PATH}/:view?`, { - template: template, - controllerAs: 'rollupJobs', - controller: class IndexRollupJobsController { - constructor($scope, $route, $injector) { - // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, - // e.g. to check license status per request. - setHttp($injector.get('$http')); - - // If returning to the app, we'll need to reset this state. - setUserHasLeftApp(false); - - $scope.$$postDigest(() => { - const appElement = document.getElementById('rollupJobsReactRoot'); - renderReact(appElement); - - const appRoute = $route.current; - const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - - const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; - - // When we navigate within rollups, prevent Angular from re-matching the route and - // rebuilding the app. - if (isNavigationInApp) { - $route.current = appRoute; - } else { - // Set internal flag so we can prevent reacting to the route change internally. - setUserHasLeftApp(true); - } - }); - - $scope.$on('$destroy', () => { - stopListeningForLocationChange(); - unmountComponentAtNode(appElement); - }); - }); - } - }, -}); - -FeatureCatalogueRegistryProvider.register(() => { - return { - id: 'rollup_jobs', - title: 'Rollups', - description: i18n.translate('xpack.rollupJobs.featureCatalogueDescription', { - defaultMessage: 'Summarize and store historical data in a smaller index for future analysis.', - }), - icon: 'indexRollupApp', - path: `#${CRUD_APP_BASE_PATH}/job_list`, - showOnHomePage: true, - category: FeatureCatalogueCategory.ADMIN, - }; -}); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/main.html b/x-pack/legacy/plugins/rollup/public/crud_app/main.html deleted file mode 100644 index 2956d157e784ce..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/crud_app/main.html +++ /dev/null @@ -1,3 +0,0 @@ - -
-
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js index 183a3765e1fd9a..de1bee29aed4de 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js @@ -6,11 +6,12 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; -class ConfirmDeleteModalUi extends Component { +export class ConfirmDeleteModal extends Component { static propTypes = { isSingleSelection: PropTypes.bool.isRequired, jobs: PropTypes.array.isRequired, @@ -19,12 +20,14 @@ class ConfirmDeleteModalUi extends Component { }; renderJobs() { - const { jobs, intl } = this.props; + const { jobs } = this.props; const jobItems = jobs.map(({ id, status }) => { - const startedMessage = intl.formatMessage({ - id: 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.startedMessage', - defaultMessage: 'started', - }); + const startedMessage = i18n.translate( + 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.startedMessage', + { + defaultMessage: 'started', + } + ); const statusText = status === 'started' ? ` (${startedMessage})` : null; return (
  • @@ -38,19 +41,19 @@ class ConfirmDeleteModalUi extends Component { } render() { - const { isSingleSelection, jobs, onCancel, onConfirm, intl } = this.props; + const { isSingleSelection, jobs, onCancel, onConfirm } = this.props; let title; let content; if (isSingleSelection) { const { id, status } = jobs[0]; - title = intl.formatMessage( + title = i18n.translate( + 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.deleteSingleJobTitle', { - id: 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.deleteSingleJobTitle', defaultMessage: "Delete rollup job '{id}'?", - }, - { id } + values: { id }, + } ); if (status === 'started') { @@ -64,12 +67,12 @@ class ConfirmDeleteModalUi extends Component { ); } } else { - title = intl.formatMessage( + title = i18n.translate( + 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.multipleDeletionTitle', { - id: 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.multipleDeletionTitle', defaultMessage: 'Delete {count} rollup jobs?', - }, - { count: jobs.length } + values: { count: jobs.length }, + } ); content = ( @@ -92,15 +95,19 @@ class ConfirmDeleteModalUi extends Component { title={title} onCancel={onCancel} onConfirm={onConfirm} - cancelButtonText={intl.formatMessage({ - id: 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.cancelButtonText', - defaultMessage: 'Cancel', - })} + cancelButtonText={i18n.translate( + 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel', + } + )} buttonColor="danger" - confirmButtonText={intl.formatMessage({ - id: 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.confirmButtonText', - defaultMessage: 'Delete', - })} + confirmButtonText={i18n.translate( + 'xpack.rollupJobs.jobActionMenu.deleteJob.confirmModal.confirmButtonText', + { + defaultMessage: 'Delete', + } + )} > {content} @@ -108,5 +115,3 @@ class ConfirmDeleteModalUi extends Component { ); } } - -export const ConfirmDeleteModal = injectI18n(ConfirmDeleteModalUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js index a8e921973efc0d..5379778c77e2f5 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js @@ -12,9 +12,9 @@ import debounce from 'lodash/function/debounce'; import first from 'lodash/array/first'; import { i18n } from '@kbn/i18n'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import chrome from 'ui/chrome'; -import { MANAGEMENT_BREADCRUMB } from 'ui/management'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/'; import { EuiCallOut, @@ -27,8 +27,6 @@ import { EuiTitle, } from '@elastic/eui'; -import { fatalError } from 'ui/notify'; - import { validateIndexPattern, formatFields, @@ -59,6 +57,8 @@ import { hasErrors, } from './steps_config'; +import { getFatalErrors } from '../../../kibana_services'; + const stepIdToTitleMap = { [STEP_LOGISTICS]: i18n.translate('xpack.rollupJobs.create.steps.stepLogisticsTitle', { defaultMessage: 'Logistics', @@ -92,7 +92,7 @@ export class JobCreateUi extends Component { constructor(props) { super(props); - chrome.breadcrumbs.set([MANAGEMENT_BREADCRUMB, listBreadcrumb, createBreadcrumb]); + props.kibana.services.setBreadcrumbs([listBreadcrumb, createBreadcrumb]); const { jobToClone: stepDefaultOverrides } = props; const stepsFields = mapValues(stepIdToStepConfigMap, step => cloneDeep(step.getDefaultFields(stepDefaultOverrides)) @@ -181,7 +181,7 @@ export class JobCreateUi extends Component { dateFields: indexPatternDateFields, numericFields, keywordFields, - } = response.data; + } = response; let indexPatternAsyncErrors; @@ -298,9 +298,9 @@ export class JobCreateUi extends Component { return; } - // Expect an error in the shape provided by Angular's $http service. - if (error && error.data) { - const { error: errorString, statusCode } = error.data; + // Expect an error in the shape provided by http service. + if (error && error.body) { + const { error: errorString, statusCode } = error.body; const indexPatternAsyncErrors = [ ({ text: name, })); -export class StepDateHistogramUi extends Component { +export class StepDateHistogram extends Component { static propTypes = { fields: PropTypes.object.isRequired, onFieldsChange: PropTypes.func.isRequired, @@ -192,7 +192,7 @@ export class StepDateHistogramUi extends Component { + ; }; } - -export const StepDateHistogram = injectI18n(StepDateHistogramUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js index 4c4019b3161a9c..9307c9074e6634 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, @@ -20,13 +20,13 @@ import { EuiTitle, } from '@elastic/eui'; -import { histogramDetailsUrl } from '../../../services'; +import { getHistogramDetailsUrl } from '../../../services'; import { FieldList } from '../../components'; import { FieldChooser, StepError } from './components'; -export class StepHistogramUi extends Component { +export class StepHistogram extends Component { static propTypes = { fields: PropTypes.object.isRequired, onFieldsChange: PropTypes.func.isRequired, @@ -96,7 +96,7 @@ export class StepHistogramUi extends Component { ; }; } - -export const StepHistogram = injectI18n(StepHistogramUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js index 8cba18804b1c6d..024001d463240b 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, @@ -26,8 +26,8 @@ import { // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { CronEditor } from '../../../../../../../../../src/plugins/es_ui_shared/public/components/cron_editor'; -import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices'; -import { logisticalDetailsUrl, cronUrl } from '../../../services'; +import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from '../../../../legacy_imports'; +import { getLogisticalDetailsUrl, getCronUrl } from '../../../services'; import { StepError } from './components'; import { indexPatterns } from '../../../../../../../../../src/plugins/data/public'; @@ -35,7 +35,7 @@ import { indexPatterns } from '../../../../../../../../../src/plugins/data/publi const indexPatternIllegalCharacters = indexPatterns.ILLEGAL_CHARACTERS_VISIBLE.join(' '); const indexIllegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' '); -export class StepLogisticsUi extends Component { +export class StepLogistics extends Component { static propTypes = { fields: PropTypes.object.isRequired, onFieldsChange: PropTypes.func.isRequired, @@ -146,7 +146,7 @@ export class StepLogisticsUi extends Component { isInvalid={Boolean(areStepErrorsVisible && errorRollupCron)} helpText={

    - + ; }; } - -export const StepLogistics = injectI18n(StepLogisticsUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js index 5022754ec5faab..b71b6bfc805bfb 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import get from 'lodash/object/get'; @@ -22,7 +22,7 @@ import { EuiButton, } from '@elastic/eui'; -import { metricsDetailsUrl } from '../../../services'; +import { getMetricsDetailsUrl } from '../../../services'; import { FieldList } from '../../components'; import { FieldChooser, StepError } from './components'; import { METRICS_CONFIG } from '../../../constants'; @@ -64,7 +64,7 @@ const metricTypesConfig = (function() { }); })(); -export class StepMetricsUi extends Component { +export class StepMetrics extends Component { static propTypes = { fields: PropTypes.object.isRequired, onFieldsChange: PropTypes.func.isRequired, @@ -247,7 +247,7 @@ export class StepMetricsUi extends Component { } getListColumns() { - return StepMetricsUi.chooserColumns.concat({ + return StepMetrics.chooserColumns.concat({ type: 'metrics', name: i18n.translate('xpack.rollupJobs.create.stepMetrics.metricsColumnHeader', { defaultMessage: 'Metrics', @@ -384,7 +384,7 @@ export class StepMetricsUi extends Component { } - columns={StepMetricsUi.chooserColumns} + columns={StepMetrics.chooserColumns} fields={metricsFields} selectedFields={metrics} onSelectField={this.onSelectField} @@ -472,5 +472,3 @@ export class StepMetricsUi extends Component { }, ]; } - -export const StepMetrics = injectI18n(StepMetricsUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js index 19937732275a22..0097792db3105a 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiErrorBoundary, EuiSpacer, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui'; @@ -30,7 +30,7 @@ const JOB_DETAILS_TABS = [ JOB_DETAILS_TAB_REQUEST, ]; -export class StepReviewUi extends Component { +export class StepReview extends Component { static propTypes = { job: PropTypes.object.isRequired, }; @@ -121,5 +121,3 @@ export class StepReviewUi extends Component { ); } } - -export const StepReview = injectI18n(StepReviewUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js index cd3c6cc5127f1a..48e045e19f478f 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, @@ -17,13 +17,13 @@ import { EuiTitle, } from '@elastic/eui'; -import { termsDetailsUrl } from '../../../services'; +import { getTermsDetailsUrl } from '../../../services'; import { FieldList } from '../../components'; import { FieldChooser } from './components'; -export class StepTermsUi extends Component { +export class StepTerms extends Component { static propTypes = { fields: PropTypes.object.isRequired, onFieldsChange: PropTypes.func.isRequired, @@ -99,7 +99,7 @@ export class StepTermsUi extends Component { @@ -251,5 +251,3 @@ export class DetailPanelUi extends Component { ); } } - -export const DetailPanel = injectI18n(DetailPanelUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js index 39153cda1f99d3..9ac8e6075e4cf3 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js @@ -58,12 +58,12 @@ describe('', () => { }); it("should have children if it's open", () => { - expect(component.find('DetailPanelUi').children().length).toBeTruthy(); + expect(component.find('DetailPanel').children().length).toBeTruthy(); }); it('should *not* have children if its closed', () => { ({ component } = initTestBed({ isOpen: false })); - expect(component.find('DetailPanelUi').children().length).toBeFalsy(); + expect(component.find('DetailPanel').children().length).toBeFalsy(); }); it('should show a loading when the job is loading', () => { diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js index 035a53206c71d5..98329a687217a7 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js @@ -6,9 +6,8 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import chrome from 'ui/chrome'; -import { MANAGEMENT_BREADCRUMB } from 'ui/management'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; import { EuiButton, @@ -26,6 +25,8 @@ import { EuiCallOut, } from '@elastic/eui'; +import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/'; + import { CRUD_APP_BASE_PATH } from '../../constants'; import { getRouterLinkProps, extractQueryParams, listBreadcrumb } from '../../services'; @@ -67,7 +68,7 @@ export class JobListUi extends Component { props.loadJobs(); - chrome.breadcrumbs.set([MANAGEMENT_BREADCRUMB, listBreadcrumb]); + props.kibana.services.setBreadcrumbs([listBreadcrumb]); this.state = {}; } @@ -97,9 +98,7 @@ export class JobListUi extends Component { } renderNoPermission() { - const { intl } = this.props; - const title = intl.formatMessage({ - id: 'xpack.rollupJobs.jobList.noPermissionTitle', + const title = i18n.translate('xpack.rollupJobs.jobList.noPermissionTitle', { defaultMessage: 'Permission error', }); return ( @@ -122,13 +121,11 @@ export class JobListUi extends Component { } renderError(error) { - // We can safely depend upon the shape of this error coming from Angular $http, because we + // We can safely depend upon the shape of this error coming from http service, because we // handle unexpected error shapes in the API action. - const { statusCode, error: errorString } = error.data; + const { statusCode, error: errorString } = error.body; - const { intl } = this.props; - const title = intl.formatMessage({ - id: 'xpack.rollupJobs.jobList.loadingErrorTitle', + const title = i18n.translate('xpack.rollupJobs.jobList.loadingErrorTitle', { defaultMessage: 'Error loading rollup jobs', }); return ( @@ -254,4 +251,4 @@ export class JobListUi extends Component { } } -export const JobList = injectI18n(JobListUi); +export const JobList = withKibana(JobListUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js index 5c7d53efbd62ce..725789fc584de5 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js @@ -4,24 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; import { registerTestBed } from '../../../../../../../test_utils'; import { rollupJobsStore } from '../../store'; import { JobList } from './job_list'; +import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; +import { coreMock } from '../../../../../../../../src/core/public/mocks'; +const startMock = coreMock.createStart(); + jest.mock('ui/new_platform'); -jest.mock('ui/chrome', () => ({ - addBasePath: () => {}, - breadcrumbs: { set: () => {} }, - getInjected: key => { - if (key === 'uiCapabilities') { - return { - navLinks: {}, - management: {}, - catalogue: {}, - }; - } - }, -})); jest.mock('../../services', () => { const services = require.requireActual('../../services'); @@ -40,7 +32,16 @@ const defaultProps = { isLoading: false, }; -const initTestBed = registerTestBed(JobList, { defaultProps, store: rollupJobsStore }); +const services = { + setBreadcrumbs: startMock.chrome.setBreadcrumbs, +}; +const Component = props => ( + + + +); + +const initTestBed = registerTestBed(Component, { defaultProps, store: rollupJobsStore }); describe('', () => { it('should render empty prompt when loading is complete and there are no jobs', () => { @@ -53,21 +54,21 @@ describe('', () => { const { component, exists } = initTestBed({ isLoading: true }); expect(exists('jobListLoading')).toBeTruthy(); - expect(component.find('JobTableUi').length).toBeFalsy(); + expect(component.find('JobTable').length).toBeFalsy(); }); it('should display the when there are jobs', () => { const { component, exists } = initTestBed({ hasJobs: true }); expect(exists('jobListLoading')).toBeFalsy(); - expect(component.find('JobTableUi').length).toBeTruthy(); + expect(component.find('JobTable').length).toBeTruthy(); }); describe('when there is an API error', () => { const { exists, find } = initTestBed({ jobLoadError: { status: 400, - data: { statusCode: 400, error: 'Houston we got a problem.' }, + body: { statusCode: 400, error: 'Houston we got a problem.' }, }, }); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js index 42d48702a3385f..4dbe396ab8410f 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js @@ -7,7 +7,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { i18n } from '@kbn/i18n'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiCheckbox, @@ -120,7 +120,7 @@ const COLUMNS = [ }, ]; -export class JobTableUi extends Component { +export class JobTable extends Component { static propTypes = { jobs: PropTypes.array, pager: PropTypes.object.isRequired, @@ -333,7 +333,7 @@ export class JobTableUi extends Component { } render() { - const { filterChanged, filter, jobs, intl, closeDetailPanel } = this.props; + const { filterChanged, filter, jobs, closeDetailPanel } = this.props; const { idToSelectedJobMap } = this.state; @@ -360,8 +360,7 @@ export class JobTableUi extends Component { filterChanged(event.target.value); }} data-test-subj="jobTableFilterInput" - placeholder={intl.formatMessage({ - id: 'xpack.rollupJobs.jobTable.searchInputPlaceholder', + placeholder={i18n.translate('xpack.rollupJobs.jobTable.searchInputPlaceholder', { defaultMessage: 'Search', })} aria-label="Search jobs" @@ -405,5 +404,3 @@ export class JobTableUi extends Component { ); } } - -export const JobTable = injectI18n(JobTableUi); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/api.js b/x-pack/legacy/plugins/rollup/public/crud_app/services/api.js index e712415f9568dc..8f95561b72d1db 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/api.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/services/api.js @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; import { UIM_JOB_CREATE, UIM_JOB_DELETE, @@ -17,39 +16,45 @@ import { import { getHttp } from './http_provider'; import { trackUserRequest } from './track_ui_metric'; -const apiPrefix = chrome.addBasePath('/api/rollup'); +const apiPrefix = '/api/rollup'; export async function loadJobs() { - const { - data: { jobs }, - } = await getHttp().get(`${apiPrefix}/jobs`); + const { jobs } = await getHttp().get(`${apiPrefix}/jobs`); return jobs; } export async function startJobs(jobIds) { const body = { jobIds }; - const request = getHttp().post(`${apiPrefix}/start`, body); + const request = getHttp().post(`${apiPrefix}/start`, { + body: JSON.stringify(body), + }); const actionType = jobIds.length > 1 ? UIM_JOB_START_MANY : UIM_JOB_START; return await trackUserRequest(request, actionType); } export async function stopJobs(jobIds) { const body = { jobIds }; - const request = getHttp().post(`${apiPrefix}/stop`, body); + const request = getHttp().post(`${apiPrefix}/stop`, { + body: JSON.stringify(body), + }); const actionType = jobIds.length > 1 ? UIM_JOB_STOP_MANY : UIM_JOB_STOP; return await trackUserRequest(request, actionType); } export async function deleteJobs(jobIds) { const body = { jobIds }; - const request = getHttp().post(`${apiPrefix}/delete`, body); + const request = getHttp().post(`${apiPrefix}/delete`, { + body: JSON.stringify(body), + }); const actionType = jobIds.length > 1 ? UIM_JOB_DELETE_MANY : UIM_JOB_DELETE; return await trackUserRequest(request, actionType); } export async function createJob(job) { const body = { job }; - const request = getHttp().put(`${apiPrefix}/create`, body); + const request = getHttp().put(`${apiPrefix}/create`, { + body: JSON.stringify(body), + }); return await trackUserRequest(request, UIM_JOB_CREATE); } diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.js b/x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.ts similarity index 54% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.js rename to x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.ts index bacaf134058982..af9e1a16e4cc5b 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fatalError, toastNotifications } from 'ui/notify'; +import { getNotifications, getFatalErrors } from '../../kibana_services'; -function createToastConfig(error, errorTitle) { - // Expect an error in the shape provided by Angular's $http service. - if (error && error.data) { - const { error: errorString, statusCode, message } = error.data; +function createToastConfig(error: any, errorTitle: string) { + // Expect an error in the shape provided by http service. + if (error && error.body) { + const { error: errorString, statusCode, message } = error.body; return { title: errorTitle, text: `${statusCode}: ${errorString}. ${message}`, @@ -17,26 +17,26 @@ function createToastConfig(error, errorTitle) { } } -export function showApiWarning(error, errorTitle) { +export function showApiWarning(error: any, errorTitle: string) { const toastConfig = createToastConfig(error, errorTitle); if (toastConfig) { - return toastNotifications.addWarning(toastConfig); + return getNotifications().toasts.addWarning(toastConfig); } // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - return fatalError(error, errorTitle); + return getFatalErrors().add(error, errorTitle); } -export function showApiError(error, errorTitle) { +export function showApiError(error: any, errorTitle: string) { const toastConfig = createToastConfig(error, errorTitle); if (toastConfig) { - return toastNotifications.addDanger(toastConfig); + return getNotifications().toasts.addDanger(toastConfig); } // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - fatalError(error, errorTitle); + getFatalErrors().add(error, errorTitle); } diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js b/x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js index 7616d8bc179c0c..ce42b26cc3e862 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js @@ -4,16 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +let esBase = ''; +let xPackBase = ''; -const esBase = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}`; -const xPackBase = `${ELASTIC_WEBSITE_URL}guide/en/x-pack/${DOC_LINK_VERSION}`; +export function setEsBaseAndXPackBase(elasticWebsiteUrl, docLinksVersion) { + esBase = `${elasticWebsiteUrl}guide/en/elasticsearch/reference/${docLinksVersion}`; + xPackBase = `${elasticWebsiteUrl}guide/en/x-pack/${docLinksVersion}`; +} -export const logisticalDetailsUrl = `${esBase}/rollup-job-config.html#_logistical_details`; -export const dateHistogramDetailsUrl = `${esBase}/rollup-job-config.html#_date_histogram_2`; -export const termsDetailsUrl = `${esBase}/rollup-job-config.html#_terms_2`; -export const histogramDetailsUrl = `${esBase}/rollup-job-config.html#_histogram_2`; -export const metricsDetailsUrl = `${esBase}/rollup-job-config.html#rollup-metrics-config`; +export const getLogisticalDetailsUrl = () => `${esBase}/rollup-job-config.html#_logistical_details`; +export const getDateHistogramDetailsUrl = () => + `${esBase}/rollup-job-config.html#_date_histogram_2`; +export const getTermsDetailsUrl = () => `${esBase}/rollup-job-config.html#_terms_2`; +export const getHistogramDetailsUrl = () => `${esBase}/rollup-job-config.html#_histogram_2`; +export const getMetricsDetailsUrl = () => `${esBase}/rollup-job-config.html#rollup-metrics-config`; -export const dateHistogramAggregationUrl = `${esBase}/search-aggregations-bucket-datehistogram-aggregation.html`; -export const cronUrl = `${xPackBase}/trigger-schedule.html#_cron_expressions`; +export const getDateHistogramAggregationUrl = () => + `${esBase}/search-aggregations-bucket-datehistogram-aggregation.html`; +export const getCronUrl = () => `${xPackBase}/trigger-schedule.html#_cron_expressions`; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.js b/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts similarity index 61% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.js rename to x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts index 835a7bdc09d869..dd84328084d050 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts @@ -4,14 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -// This is an Angular service, which is why we use this provider pattern to access it within -// our React app. -let _http; +import { HttpStart } from 'src/core/public'; -export function setHttp(http) { +let _http: HttpStart | null = null; + +export function setHttp(http: HttpStart) { _http = http; } export function getHttp() { + if (!_http) { + throw new Error('Rollup http is not defined'); + } return _http; } diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js b/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js index 74ed8d8c325c0c..790770b9b6a9f4 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js @@ -11,13 +11,14 @@ export { showApiError, showApiWarning } from './api_errors'; export { listBreadcrumb, createBreadcrumb } from './breadcrumbs'; export { - logisticalDetailsUrl, - dateHistogramDetailsUrl, - dateHistogramAggregationUrl, - termsDetailsUrl, - histogramDetailsUrl, - metricsDetailsUrl, - cronUrl, + setEsBaseAndXPackBase, + getLogisticalDetailsUrl, + getDateHistogramDetailsUrl, + getDateHistogramAggregationUrl, + getTermsDetailsUrl, + getHistogramDetailsUrl, + getMetricsDetailsUrl, + getCronUrl, } from './documentation_links'; export { filterItems } from './filter_items'; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js b/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js index 163860b7f24c65..c85b4c55f665e1 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js @@ -5,7 +5,6 @@ */ import { i18n } from '@kbn/i18n'; -import { fatalError } from 'ui/notify'; import { CRUD_APP_BASE_PATH } from '../../constants'; import { @@ -24,6 +23,8 @@ import { CLEAR_CREATE_JOB_ERRORS, } from '../action_types'; +import { getFatalErrors } from '../../../kibana_services'; + export const createJob = jobConfig => async dispatch => { dispatch({ type: CREATE_JOB_START, @@ -39,12 +40,13 @@ export const createJob = jobConfig => async dispatch => { ]); } catch (error) { if (error) { - const { statusCode, data } = error; + const { body } = error; + const statusCode = error.statusCode || (body && body.statusCode); - // Expect an error in the shape provided by Angular's $http service. - if (data) { + // Expect an error in the shape provided by http service. + if (body) { // Some errors have statusCode directly available but some are under a data property. - if ((statusCode || (data && data.statusCode)) === 409) { + if (statusCode === 409) { return dispatch({ type: CREATE_JOB_FAILURE, payload: { @@ -67,9 +69,9 @@ export const createJob = jobConfig => async dispatch => { error: { message: i18n.translate('xpack.rollupJobs.createAction.failedDefaultErrorMessage', { defaultMessage: 'Request failed with a {statusCode} error. {message}', - values: { statusCode, message: data.message }, + values: { statusCode, message: body.message }, }), - cause: data.cause, + cause: body.cause, }, }, }); @@ -78,7 +80,7 @@ export const createJob = jobConfig => async dispatch => { // This error isn't an HTTP error, so let the fatal error screen tell the user something // unexpected happened. - return fatalError( + return getFatalErrors().add( error, i18n.translate('xpack.rollupJobs.createAction.errorTitle', { defaultMessage: 'Error creating rollup job', @@ -86,7 +88,7 @@ export const createJob = jobConfig => async dispatch => { ); } - const deserializedJob = deserializeJob(newJob.data); + const deserializedJob = deserializeJob(newJob); dispatch({ type: CREATE_JOB_SUCCESS, diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js b/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js index d700ec69839be6..0cfc8c24d46e95 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js @@ -5,7 +5,6 @@ */ import { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; import { deleteJobs as sendDeleteJobsRequest, @@ -19,6 +18,8 @@ import { UPDATE_JOB_START, UPDATE_JOB_SUCCESS, UPDATE_JOB_FAILURE } from '../act import { refreshJobs } from './refresh_jobs'; import { closeDetailPanel } from './detail_panel'; +import { getNotifications } from '../../../kibana_services'; + export const deleteJobs = jobIds => async (dispatch, getState) => { dispatch({ type: UPDATE_JOB_START, @@ -40,14 +41,14 @@ export const deleteJobs = jobIds => async (dispatch, getState) => { } if (jobIds.length === 1) { - toastNotifications.addSuccess( + getNotifications().toasts.addSuccess( i18n.translate('xpack.rollupJobs.deleteAction.successSingleNotificationTitle', { defaultMessage: `Rollup job '{jobId}' was deleted`, values: { jobId: jobIds[0] }, }) ); } else { - toastNotifications.addSuccess( + getNotifications().toasts.addSuccess( i18n.translate('xpack.rollupJobs.deleteAction.successMultipleNotificationTitle', { defaultMessage: '{count} rollup jobs were deleted', values: { count: jobIds.length }, diff --git a/x-pack/legacy/plugins/rollup/public/extend_index_management/index.js b/x-pack/legacy/plugins/rollup/public/extend_index_management/index.ts similarity index 76% rename from x-pack/legacy/plugins/rollup/public/extend_index_management/index.js rename to x-pack/legacy/plugins/rollup/public/extend_index_management/index.ts index 5e14d3eabc9a60..1a34811901bbe7 100644 --- a/x-pack/legacy/plugins/rollup/public/extend_index_management/index.js +++ b/x-pack/legacy/plugins/rollup/public/extend_index_management/index.ts @@ -4,15 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { - addToggleExtension, - addBadgeExtension, -} from '../../../index_management/public/index_management_extensions'; import { get } from 'lodash'; const propertyPath = 'isRollupIndex'; export const rollupToggleExtension = { - matchIndex: index => { + matchIndex: (index: { isRollupIndex: boolean }) => { return get(index, propertyPath); }, label: i18n.translate('xpack.rollupJobs.indexMgmtToggle.toggleLabel', { @@ -20,8 +16,9 @@ export const rollupToggleExtension = { }), name: 'rollupToggle', }; + export const rollupBadgeExtension = { - matchIndex: index => { + matchIndex: (index: { isRollupIndex: boolean }) => { return get(index, propertyPath); }, label: i18n.translate('xpack.rollupJobs.indexMgmtBadge.rollupLabel', { @@ -30,6 +27,3 @@ export const rollupBadgeExtension = { color: 'secondary', filterExpression: 'isRollupIndex:true', }; - -addBadgeExtension(rollupBadgeExtension); -addToggleExtension(rollupToggleExtension); diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/index.js b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/index.js deleted file mode 100644 index 1add469e073bd8..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/index.js +++ /dev/null @@ -1,17 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; - -import { initIndexPatternCreation } from './register'; -import { CONFIG_ROLLUPS } from '../../common'; - -const uiSettings = chrome.getUiSettingsClient(); -const isRollupIndexPatternsEnabled = uiSettings.get(CONFIG_ROLLUPS); - -if (isRollupIndexPatternsEnabled) { - initIndexPatternCreation(); -} diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/register.js b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/register.js deleted file mode 100644 index 9a3aed548dcc9c..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/register.js +++ /dev/null @@ -1,12 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { setup as managementSetup } from '../../../../../../src/legacy/core_plugins/management/public/legacy'; -import { RollupIndexPatternCreationConfig } from './rollup_index_pattern_creation_config'; - -export function initIndexPatternCreation() { - managementSetup.indexPattern.creation.add(RollupIndexPatternCreationConfig); -} diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js index 07f2a674decc5d..82a4c5a888594e 100644 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js +++ b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js @@ -6,10 +6,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { npSetup } from 'ui/new_platform'; import { RollupPrompt } from './components/rollup_prompt'; -import { setHttpClient, getRollupIndices } from '../services/api'; import { IndexPatternCreationConfig } from '../../../../../../src/legacy/core_plugins/management/public'; const rollupIndexPatternTypeName = i18n.translate( @@ -54,7 +52,6 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig ...options, }); - setHttpClient(this.httpClient); this.rollupIndex = null; this.rollupJobs = []; this.rollupIndicesCapabilities = {}; @@ -67,9 +64,10 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig // This is a hack intended to prevent the getRollupIndices() request from being sent if // we're on /logout. There is a race condition that can arise on that page, whereby this // request resolves after the logout request resolves, and un-clears the session ID. - const isAnonymous = npSetup.core.http.anonymousPaths.isAnonymous(window.location.pathname); + const isAnonymous = this.httpClient.anonymousPaths.isAnonymous(window.location.pathname); if (!isAnonymous) { - this.rollupIndicesCapabilities = await getRollupIndices(); + const response = await this.httpClient.get('/api/rollup/indices'); + this.rollupIndicesCapabilities = response || {}; } this.rollupIndices = Object.keys(this.rollupIndicesCapabilities); diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_list/index.js b/x-pack/legacy/plugins/rollup/public/index_pattern_list/index.js deleted file mode 100644 index 63a3149faaadb3..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_list/index.js +++ /dev/null @@ -1,16 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; -import { initIndexPatternList } from './register'; -import { CONFIG_ROLLUPS } from '../../common'; - -const uiSettings = chrome.getUiSettingsClient(); -const isRollupIndexPatternsEnabled = uiSettings.get(CONFIG_ROLLUPS); - -if (isRollupIndexPatternsEnabled) { - initIndexPatternList(); -} diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_list/register.js b/x-pack/legacy/plugins/rollup/public/index_pattern_list/register.js deleted file mode 100644 index 173c28826436bc..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_list/register.js +++ /dev/null @@ -1,12 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { setup as managementSetup } from '../../../../../../src/legacy/core_plugins/management/public/legacy'; -import { RollupIndexPatternListConfig } from './rollup_index_pattern_list_config'; - -export function initIndexPatternList() { - managementSetup.indexPattern.list.add(RollupIndexPatternListConfig); -} diff --git a/x-pack/legacy/plugins/rollup/public/kibana_services.ts b/x-pack/legacy/plugins/rollup/public/kibana_services.ts new file mode 100644 index 00000000000000..335eeb90282ca9 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/public/kibana_services.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { NotificationsStart, FatalErrorsSetup } from 'src/core/public'; + +let notifications: NotificationsStart | null = null; +let fatalErrors: FatalErrorsSetup | null = null; + +export function getNotifications() { + if (!notifications) { + throw new Error('Rollup notifications is not defined'); + } + return notifications; +} +export function setNotifications(newNotifications: NotificationsStart) { + notifications = newNotifications; +} + +export function getFatalErrors() { + if (!fatalErrors) { + throw new Error('Rollup fatalErrors is not defined'); + } + return fatalErrors; +} +export function setFatalErrors(newFatalErrors: FatalErrorsSetup) { + fatalErrors = newFatalErrors; +} diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts new file mode 100644 index 00000000000000..a2738372ff346f --- /dev/null +++ b/x-pack/legacy/plugins/rollup/public/legacy.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { npSetup, npStart } from 'ui/new_platform'; +import { editorConfigProviders } from 'ui/vis/config'; +import { aggTypeFilters } from 'ui/agg_types/filter'; +import { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; +import { addSearchStrategy } from '../../../../../src/plugins/data/public'; +import { RollupPlugin } from './plugin'; +import { setup as management } from '../../../../../src/legacy/core_plugins/management/public/legacy'; +import { addBadgeExtension, addToggleExtension } from '../../index_management/public'; + +const plugin = new RollupPlugin(); + +export const setup = plugin.setup(npSetup.core, { + ...npSetup.plugins, + __LEGACY: { + aggTypeFilters, + aggTypeFieldFilters, + editorConfigProviders, + addSearchStrategy, + addBadgeExtension, + addToggleExtension, + managementLegacy: management, + }, +}); +export const start = plugin.start(npStart.core); diff --git a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts new file mode 100644 index 00000000000000..981f97963591e7 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// @ts-ignore +export { findIllegalCharactersInIndexName, INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices'; + +export { AggTypeFilters } from 'ui/agg_types/filter'; +export { AggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; +export { EditorConfigProviderRegistry } from 'ui/vis/config'; diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/legacy/plugins/rollup/public/plugin.ts new file mode 100644 index 00000000000000..97c03fd1fdfc25 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/public/plugin.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { + EditorConfigProviderRegistry, + AggTypeFilters, + AggTypeFieldFilters, +} from './legacy_imports'; +import { SearchStrategyProvider } from '../../../../../src/plugins/data/public'; +import { ManagementSetup as ManagementSetupLegacy } from '../../../../../src/legacy/core_plugins/management/public/np_ready'; +import { rollupBadgeExtension, rollupToggleExtension } from './extend_index_management'; +// @ts-ignore +import { RollupIndexPatternCreationConfig } from './index_pattern_creation/rollup_index_pattern_creation_config'; +// @ts-ignore +import { RollupIndexPatternListConfig } from './index_pattern_list/rollup_index_pattern_list_config'; +import { getRollupSearchStrategy } from './search/rollup_search_strategy'; +// @ts-ignore +import { initAggTypeFilter } from './visualize/agg_type_filter'; +// @ts-ignore +import { initAggTypeFieldFilter } from './visualize/agg_type_field_filter'; +// @ts-ignore +import { initEditorConfig } from './visualize/editor_config'; +import { CONFIG_ROLLUPS } from '../common'; +import { + FeatureCatalogueCategory, + HomePublicPluginSetup, +} from '../../../../../src/plugins/home/public'; +// @ts-ignore +import { CRUD_APP_BASE_PATH } from './crud_app/constants'; +import { ManagementSetup } from '../../../../../src/plugins/management/public'; +// @ts-ignore +import { setEsBaseAndXPackBase, setHttp } from './crud_app/services'; +import { setNotifications, setFatalErrors } from './kibana_services'; +import { renderApp } from './application'; + +export interface RollupPluginSetupDependencies { + __LEGACY: { + aggTypeFilters: AggTypeFilters; + aggTypeFieldFilters: AggTypeFieldFilters; + editorConfigProviders: EditorConfigProviderRegistry; + addSearchStrategy: (searchStrategy: SearchStrategyProvider) => void; + managementLegacy: ManagementSetupLegacy; + addBadgeExtension: (badgeExtension: any) => void; + addToggleExtension: (toggleExtension: any) => void; + }; + home?: HomePublicPluginSetup; + management: ManagementSetup; +} + +export class RollupPlugin implements Plugin { + setup( + core: CoreSetup, + { + __LEGACY: { + aggTypeFilters, + aggTypeFieldFilters, + editorConfigProviders, + addSearchStrategy, + managementLegacy, + addBadgeExtension, + addToggleExtension, + }, + home, + management, + }: RollupPluginSetupDependencies + ) { + setFatalErrors(core.fatalErrors); + addBadgeExtension(rollupBadgeExtension); + addToggleExtension(rollupToggleExtension); + + const isRollupIndexPatternsEnabled = core.uiSettings.get(CONFIG_ROLLUPS); + + if (isRollupIndexPatternsEnabled) { + managementLegacy.indexPattern.creation.add(RollupIndexPatternCreationConfig); + managementLegacy.indexPattern.list.add(RollupIndexPatternListConfig); + addSearchStrategy(getRollupSearchStrategy(core.http.fetch)); + initAggTypeFilter(aggTypeFilters); + initAggTypeFieldFilter(aggTypeFieldFilters); + initEditorConfig(editorConfigProviders); + } + + if (home) { + home.featureCatalogue.register({ + id: 'rollup_jobs', + title: 'Rollups', + description: i18n.translate('xpack.rollupJobs.featureCatalogueDescription', { + defaultMessage: + 'Summarize and store historical data in a smaller index for future analysis.', + }), + icon: 'indexRollupApp', + path: `#${CRUD_APP_BASE_PATH}/job_list`, + showOnHomePage: true, + category: FeatureCatalogueCategory.ADMIN, + }); + } + + const esSection = management.sections.getSection('elasticsearch'); + if (esSection) { + esSection.registerApp({ + id: 'rollup_jobs', + title: i18n.translate('xpack.rollupJobs.appTitle', { defaultMessage: 'Rollup Jobs' }), + order: 3, + mount(params) { + params.setBreadcrumbs([ + { + text: i18n.translate('xpack.rollupJobs.breadcrumbsTitle', { + defaultMessage: 'Rollup Jobs', + }), + }, + ]); + + return renderApp(core, params); + }, + }); + } + } + + start(core: CoreStart) { + setHttp(core.http); + setNotifications(core.notifications); + setEsBaseAndXPackBase(core.docLinks.ELASTIC_WEBSITE_URL, core.docLinks.DOC_LINK_VERSION); + } +} diff --git a/x-pack/legacy/plugins/rollup/public/search/index.js b/x-pack/legacy/plugins/rollup/public/search/index.js deleted file mode 100644 index e76ba4817d72c6..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/search/index.js +++ /dev/null @@ -1,17 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; - -import { initSearch } from './register'; -import { CONFIG_ROLLUPS } from '../../common'; - -const uiSettings = chrome.getUiSettingsClient(); -const isRollupIndexPatternsEnabled = uiSettings.get(CONFIG_ROLLUPS); - -if (isRollupIndexPatternsEnabled) { - initSearch(); -} diff --git a/x-pack/legacy/plugins/rollup/public/search/register.js b/x-pack/legacy/plugins/rollup/public/search/register.js deleted file mode 100644 index 05db100088e8a9..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/search/register.js +++ /dev/null @@ -1,12 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { addSearchStrategy } from '../../../../../../src/plugins/data/public'; -import { rollupSearchStrategy } from './rollup_search_strategy'; - -export function initSearch() { - addSearchStrategy(rollupSearchStrategy); -} diff --git a/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.js b/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts similarity index 74% rename from x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.js rename to x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts index 18e72cdf0fd3dc..4709c0aa498f81 100644 --- a/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.js +++ b/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts @@ -4,10 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { kfetch } from 'ui/kfetch'; -import { SearchError, getSearchErrorType } from '../../../../../../src/plugins/data/public'; +import { HttpSetup } from 'src/core/public'; +import { + SearchError, + getSearchErrorType, + IIndexPattern, + SearchStrategyProvider, + SearchResponse, + SearchRequest, +} from '../../../../../../src/plugins/data/public'; -function serializeFetchParams(searchRequests) { +function serializeFetchParams(searchRequests: SearchRequest[]) { return JSON.stringify( searchRequests.map(searchRequestWithFetchParams => { const indexPattern = @@ -17,7 +24,7 @@ function serializeFetchParams(searchRequests) { } = searchRequestWithFetchParams; const query = { - size: size, + size, aggregations: aggs, query: _query, }; @@ -30,7 +37,7 @@ function serializeFetchParams(searchRequests) { // Rollup search always returns 0 hits, but visualizations expect search responses // to return hits > 0, otherwise they do not render. We fake the number of hits here // by counting the number of aggregation buckets/values returned by rollup search. -function shimHitsInFetchResponse(response) { +function shimHitsInFetchResponse(response: SearchResponse[]) { return response.map(result => { const buckets = result.aggregations ? Object.keys(result.aggregations).reduce((allBuckets, agg) => { @@ -51,17 +58,16 @@ function shimHitsInFetchResponse(response) { }); } -export const rollupSearchStrategy = { +export const getRollupSearchStrategy = (fetch: HttpSetup['fetch']): SearchStrategyProvider => ({ id: 'rollup', - search: ({ searchRequests, Promise }) => { + search: ({ searchRequests }) => { // Serialize the fetch params into a format suitable for the body of an ES query. const serializedFetchParams = serializeFetchParams(searchRequests); const controller = new AbortController(); - const promise = kfetch({ + const promise = fetch('../api/rollup/search', { signal: controller.signal, - pathname: '../api/rollup/search', method: 'POST', body: serializedFetchParams, }); @@ -69,17 +75,17 @@ export const rollupSearchStrategy = { return { searching: promise.then(shimHitsInFetchResponse).catch(error => { const { - body: { statusText, error: title, message }, + body: { statusCode, error: title, message }, res: { url }, } = error; - // Format kfetch error as a SearchError. + // Format fetch error as a SearchError. const searchError = new SearchError({ - status: statusText, + status: statusCode, title, message: `Rollup search error: ${message}`, path: url, - type: getSearchErrorType({ message }), + type: getSearchErrorType({ message }) || '', }); return Promise.reject(searchError); @@ -88,11 +94,11 @@ export const rollupSearchStrategy = { }; }, - isViable: indexPattern => { + isViable: (indexPattern: IIndexPattern) => { if (!indexPattern) { return false; } return indexPattern.type === 'rollup'; }, -}; +}); diff --git a/x-pack/legacy/plugins/rollup/public/services/api.js b/x-pack/legacy/plugins/rollup/public/services/api.js deleted file mode 100644 index ae9e8756c7efc9..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/services/api.js +++ /dev/null @@ -1,14 +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; - * you may not use this file except in compliance with the Elastic License. - */ -let httpClient; -export const setHttpClient = client => { - httpClient = client; -}; - -export async function getRollupIndices() { - const response = await httpClient.get('/api/rollup/indices'); - return response || {}; -} diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js index 9d19dff648667e..6f44e0ef90efd9 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; - -export function initAggTypeFieldFilter() { +export function initAggTypeFieldFilter(aggTypeFieldFilters) { /** * If rollup index pattern, check its capabilities * and limit available fields for a given aggType based on that. diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js index 75b11dac06cf53..5f9fab3061a194 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { aggTypeFilters } from 'ui/agg_types/filter'; - -export function initAggTypeFilter() { +export function initAggTypeFilter(aggTypeFilters) { /** * If rollup index pattern, check its capabilities * and limit available aggregations based on that. diff --git a/x-pack/legacy/plugins/rollup/public/visualize/editor_config.js b/x-pack/legacy/plugins/rollup/public/visualize/editor_config.js index 8f5072e8a98669..5c1eb7c8ee3b75 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/editor_config.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/editor_config.js @@ -5,9 +5,8 @@ */ import { i18n } from '@kbn/i18n'; -import { editorConfigProviders } from 'ui/vis/config'; -export function initEditorConfig() { +export function initEditorConfig(editorConfigProviders) { // Limit agg params based on rollup capabilities editorConfigProviders.register((indexPattern, aggConfig) => { if (indexPattern.type !== 'rollup') { diff --git a/x-pack/legacy/plugins/rollup/public/visualize/index.js b/x-pack/legacy/plugins/rollup/public/visualize/index.js deleted file mode 100644 index e5a9c63c91a92f..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/visualize/index.js +++ /dev/null @@ -1,21 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; - -import { initAggTypeFilter } from './agg_type_filter'; -import { initAggTypeFieldFilter } from './agg_type_field_filter'; -import { initEditorConfig } from './editor_config'; -import { CONFIG_ROLLUPS } from '../../common'; - -const uiSettings = chrome.getUiSettingsClient(); -const isRollupIndexPatternsEnabled = uiSettings.get(CONFIG_ROLLUPS); - -if (isRollupIndexPatternsEnabled) { - initAggTypeFilter(); - initAggTypeFieldFilter(); - initEditorConfig(); -} From 952b61e049f803acd20c8bbedec5d35aa3f384ff Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 30 Jan 2020 10:51:02 +0100 Subject: [PATCH 06/69] [Console] Move out of legacy + migrate server side to New Platform (#55690) * Initial move of public and setup of server skeleton * Fix public paths and types * Use new usage stats dependency directly in tracker also mark as an optional dependency * WiP on getting server side working * Restore proxy route behaviour for base case, still need to test custom proxy and SSL * Add new type and lib files * Clean up legacy start up code and add comment about issue in kibana.yml config for console * Move console_extensions to new platform and introduce ConsoleSetup API for extending autocomplete Add TODO regarding exposing legacy ES config * Re-introduce injected elasticsearch variable and use it in public * Don't pass stateSetter prop through to checkbox * Refactor of proxy route (split into separate files). Easier testing for now. Refactor file name of request.ts -> proxy_request.ts. This is consistent with the exported function now Started fixing server side tests for the proxy route - Migrated away from sinon - Completed the body.js -> body.test.ts. Still have to do the rest * headers.js test -> headers.test.ts and moved some of the proxy route mocking logic to a common space * Finish migration of rest of proxy route test away from hapi Add test for custom route validation * Bring console application in line with https://github.com/elastic/kibana/blob/master/src/core/CONVENTIONS.md#applications Change log from info level to debug level for console_extensions plugin * Update i18nrc file for console * Add setHeaders when passing back error response Co-authored-by: Elastic Machine --- .github/CODEOWNERS | 4 +- .i18nrc.json | 2 +- .../server/http/router/response_adapter.ts | 13 +- .../core_plugins/console/__tests__/index.js | 75 ------ src/legacy/core_plugins/console/index.ts | 187 --------------- src/legacy/core_plugins/console/package.json | 8 - .../core_plugins/console/public/legacy.ts | 53 ----- .../server/__tests__/proxy_route/headers.js | 96 -------- .../server/__tests__/proxy_route/params.js | 170 -------------- .../__tests__/proxy_route/query_string.js | 137 ----------- .../console/server/proxy_route.ts | 171 -------------- .../core_plugins/console_legacy/index.ts | 51 ++++ .../core_plugins/console_legacy/package.json | 4 + .../public}/styles/_app.scss | 0 .../public}/styles/components/_help.scss | 0 .../public}/styles/components/_history.scss | 0 .../public}/styles/components/_index.scss | 0 .../public}/styles/index.scss | 0 .../console/common/text_object.ts | 0 src/plugins/console/common/types/index.ts | 21 ++ .../console/common/types/models.ts} | 2 +- .../console/common/types/plugin_config.ts | 22 ++ .../public => plugins/console}/kibana.json | 2 +- .../application/components/console_menu.tsx | 0 .../components/editor_content_spinner.tsx | 0 .../application/components/editor_example.tsx | 0 .../application/components/help_panel.tsx | 0 .../public}/application/components/index.ts | 0 .../application/components/settings_modal.tsx | 5 +- .../something_went_wrong_callout.tsx | 0 .../application/components/top_nav_menu.tsx | 0 .../application/components/welcome_panel.tsx | 0 .../application/constants/help_example.txt | 0 .../console_history/console_history.tsx | 0 .../console_history/history_viewer.tsx | 0 .../containers/console_history/index.ts | 0 .../application/containers/editor/editor.tsx | 2 +- .../application/containers/editor/index.ts | 0 .../console_editor/apply_editor_settings.ts | 0 .../console_editor/editor.test.mock.tsx | 0 .../legacy/console_editor/editor.test.tsx | 2 +- .../editor/legacy/console_editor/editor.tsx | 0 .../legacy/console_editor/editor_output.tsx | 0 .../editor/legacy/console_editor/index.ts | 0 .../console_editor/keyboard_shortcuts.ts | 0 .../editor/legacy/console_menu_actions.ts | 0 .../containers/editor/legacy/index.ts | 0 .../subscribe_console_resize_checker.ts | 3 +- .../legacy/use_ui_ace_keyboard_mode.tsx | 0 .../public}/application/containers/index.ts | 0 .../containers/main/get_top_nav.ts | 0 .../application/containers/main/index.ts | 0 .../application/containers/main/main.tsx | 0 .../application/containers/settings.tsx | 0 .../contexts/create_use_context.ts | 0 .../editor_context/editor_context.tsx | 0 .../editor_context/editor_registry.ts | 0 .../contexts/editor_context/index.ts | 0 .../public}/application/contexts/index.ts | 0 .../application/contexts/request_context.tsx | 0 .../application/contexts/services_context.tsx | 2 +- .../public}/application/factories/index.ts | 0 .../application/factories/token_iterator.ts | 0 .../public}/application/hooks/index.ts | 0 .../hooks/use_data_init/data_migration.ts | 2 +- .../application/hooks/use_data_init/index.ts | 0 .../hooks/use_data_init/use_data_init.ts | 0 .../use_restore_request_from_history/index.ts | 0 .../restore_request_from_history.ts | 0 .../use_restore_request_from_history.ts | 0 .../hooks/use_save_current_text_object.ts | 0 .../use_send_current_request_to_es/index.ts | 0 .../send_request_to_es.ts | 0 .../use_send_current_request_to_es/track.ts | 0 .../use_send_current_request_to_es.ts | 0 .../application/hooks/use_set_input_editor.ts | 0 .../console/public}/application/index.tsx | 26 ++- .../console/public}/application/logo.svg | 0 .../public}/application/models/index.ts | 0 .../__tests__/input_tokenization.test.js | 0 .../__tests__/output_tokenization.test.js | 0 .../models/legacy_core_editor/create.ts | 0 .../legacy_core_editor/create_readonly.ts | 0 .../models/legacy_core_editor/index.ts | 0 .../legacy_core_editor.test.mocks.ts | 0 .../legacy_core_editor/legacy_core_editor.ts | 0 .../mode/elasticsearch_sql_highlight_rules.ts | 0 .../models/legacy_core_editor/mode/input.js | 0 .../mode/input_highlight_rules.js | 0 .../models/legacy_core_editor/mode/output.js | 0 .../mode/output_highlight_rules.js | 0 .../models/legacy_core_editor/mode/script.js | 0 .../mode/script_highlight_rules.js | 0 .../legacy_core_editor/mode/worker/index.js | 0 .../legacy_core_editor/mode/worker/worker.js | 0 .../mode/x_json_highlight_rules.js | 0 .../models/legacy_core_editor/smart_resize.ts | 0 .../legacy_core_editor/theme_sense_dark.js | 0 .../sense_editor/__tests__/editor_input1.txt | 0 .../__tests__/integration.test.js | 0 .../__tests__/sense_editor.test.js | 0 .../application/models/sense_editor/create.ts | 0 .../application/models/sense_editor/curl.ts | 0 .../application/models/sense_editor/index.ts | 0 .../sense_editor/sense_editor.test.mocks.ts | 0 .../models/sense_editor/sense_editor.ts | 0 .../public}/application/stores/editor.ts | 2 +- .../public}/application/stores/request.ts | 0 .../console/public}/index.ts | 6 +- .../public}/lib/ace_token_provider/index.ts | 0 .../ace_token_provider/token_provider.test.ts | 0 .../lib/ace_token_provider/token_provider.ts | 0 .../__tests__/url_autocomplete.test.js | 0 .../autocomplete/__tests__/url_params.test.js | 0 .../public}/lib/autocomplete/autocomplete.ts | 0 .../lib/autocomplete/body_completer.js | 0 .../components/accept_endpoint_component.js | 0 .../components/autocomplete_component.js | 0 .../components/conditional_proxy.js | 0 .../components/constant_component.js | 0 .../field_autocomplete_component.js | 0 .../components/full_request_component.ts | 0 .../components/global_only_component.js | 0 .../components/id_autocomplete_component.js | 0 .../lib/autocomplete/components/index.js | 0 .../index_autocomplete_component.js | 0 .../autocomplete/components/list_component.js | 0 .../components/object_component.js | 0 .../components/shared_component.js | 0 .../components/simple_param_component.js | 0 .../template_autocomplete_component.js | 0 .../components/type_autocomplete_component.js | 0 .../components/url_pattern_matcher.js | 0 .../username_autocomplete_component.js | 0 .../public}/lib/autocomplete/engine.js | 0 .../get_endpoint_from_position.ts | 0 .../public}/lib/autocomplete/url_params.js | 0 .../__tests__/curl_parsing.test.js | 0 .../curl_parsing/__tests__/curl_parsing.txt | 0 .../console/public}/lib/curl_parsing/curl.js | 0 .../lib/es/__tests__/content_type.test.js | 0 .../console/public}/lib/es/es.js | 0 .../public}/lib/kb/__tests__/kb.test.js | 0 .../console/public}/lib/kb/api.js | 0 .../console/public}/lib/kb/index.js | 0 .../console/public}/lib/kb/kb.js | 0 .../lib/local_storage_object_client/create.ts | 4 +- .../lib/local_storage_object_client/index.ts | 0 .../local_storage_object_client.ts | 2 +- .../lib/mappings/__tests__/mapping.test.js | 0 .../console/public}/lib/mappings/mappings.js | 0 .../console/public}/lib/row_parser.ts | 0 .../public}/lib/token_iterator/index.ts | 0 .../lib/token_iterator/token_iterator.test.ts | 0 .../lib/token_iterator/token_iterator.ts | 0 .../public}/lib/utils/__tests__/utils.test.js | 0 .../__tests__/utils_string_collapsing.txt | 0 .../__tests__/utils_string_expanding.txt | 0 .../console/public}/lib/utils/utils.ts | 0 .../console/public}/plugin.ts | 53 +++-- .../console/public}/services/history.ts | 0 .../console/public}/services/index.ts | 0 .../console/public}/services/settings.ts | 0 .../console/public}/services/storage.ts | 0 .../console/public}/services/tracker.ts | 19 +- .../console/public}/types/common.ts | 0 .../console/public}/types/core_editor.ts | 0 .../console/public}/types/index.ts | 1 + .../public/types/plugin_dependencies.ts | 27 +++ .../console/public}/types/token.ts | 0 .../console/public}/types/tokens_provider.ts | 0 .../__tests__/elasticsearch_proxy_config.js | 2 +- .../console/server/__tests__/proxy_config.js | 2 +- .../__tests__/proxy_config_collection.js | 2 +- .../__tests__/proxy_route/body.test.ts} | 64 +++--- .../__tests__/proxy_route/headers.test.ts | 89 +++++++ .../server/__tests__/proxy_route/mocks.ts | 44 ++++ .../__tests__/proxy_route/params.test.ts | 87 +++++++ .../proxy_route/query_string.test.ts | 76 ++++++ .../proxy_route/route_validation.test.ts | 52 +++++ .../server/__tests__/proxy_route/stubs.ts} | 36 ++- .../console/server/__tests__/set_headers.js | 2 +- .../server/__tests__/wildcard_matcher.js | 2 +- src/plugins/console/server/config.ts | 55 +++++ src/plugins/console/server/index.ts | 31 +++ .../server/lib}/elasticsearch_proxy_config.ts | 3 +- .../console/server/lib/index.ts} | 5 +- .../console/server/lib/proxy_config.ts} | 30 ++- .../server/lib/proxy_config_collection.ts} | 14 +- .../console/server/lib/proxy_request.test.ts} | 4 +- .../console/server/lib/proxy_request.ts} | 2 +- .../console/server/lib/set_headers.ts} | 2 +- .../server/lib/spec_definitions}/api.js | 0 .../server/lib/spec_definitions}/es_6_0.js | 0 .../spec_definitions}/es_6_0/aggregations.js | 0 .../lib/spec_definitions}/es_6_0/aliases.js | 0 .../lib/spec_definitions}/es_6_0/document.js | 0 .../lib/spec_definitions}/es_6_0/filter.js | 0 .../lib/spec_definitions}/es_6_0/globals.js | 0 .../lib/spec_definitions}/es_6_0/ingest.js | 0 .../lib/spec_definitions}/es_6_0/mappings.js | 0 .../lib/spec_definitions}/es_6_0/query/dsl.js | 0 .../spec_definitions}/es_6_0/query/index.js | 0 .../es_6_0/query/templates.js | 0 .../lib/spec_definitions}/es_6_0/reindex.js | 0 .../lib/spec_definitions}/es_6_0/search.js | 0 .../server/lib/spec_definitions/index.d.ts | 24 ++ .../server/lib/spec_definitions/index.js | 24 ++ .../server/lib/spec_definitions}/server.js | 4 +- .../lib/spec_definitions}/server.test.js | 0 .../lib/spec_definitions}/spec/.eslintrc | 0 .../spec/generated/_common.json | 0 .../spec/generated/bulk.json | 0 .../spec/generated/cat.aliases.json | 0 .../spec/generated/cat.allocation.json | 0 .../spec/generated/cat.count.json | 0 .../spec/generated/cat.fielddata.json | 0 .../spec/generated/cat.health.json | 0 .../spec/generated/cat.help.json | 0 .../spec/generated/cat.indices.json | 0 .../spec/generated/cat.master.json | 0 .../spec/generated/cat.nodeattrs.json | 0 .../spec/generated/cat.nodes.json | 0 .../spec/generated/cat.pending_tasks.json | 0 .../spec/generated/cat.plugins.json | 0 .../spec/generated/cat.recovery.json | 0 .../spec/generated/cat.repositories.json | 0 .../spec/generated/cat.segments.json | 0 .../spec/generated/cat.shards.json | 0 .../spec/generated/cat.snapshots.json | 0 .../spec/generated/cat.tasks.json | 0 .../spec/generated/cat.templates.json | 0 .../spec/generated/cat.thread_pool.json | 0 .../spec/generated/clear_scroll.json | 0 .../generated/cluster.allocation_explain.json | 0 .../spec/generated/cluster.get_settings.json | 0 .../spec/generated/cluster.health.json | 0 .../spec/generated/cluster.pending_tasks.json | 0 .../spec/generated/cluster.put_settings.json | 0 .../spec/generated/cluster.remote_info.json | 0 .../spec/generated/cluster.reroute.json | 0 .../spec/generated/cluster.state.json | 0 .../spec/generated/cluster.stats.json | 0 .../spec/generated/count.json | 0 .../spec/generated/create.json | 0 .../spec/generated/delete.json | 0 .../spec/generated/delete_by_query.json | 0 .../generated/delete_by_query_rethrottle.json | 0 .../spec/generated/delete_script.json | 0 .../spec/generated/exists.json | 0 .../spec/generated/exists_source.json | 0 .../spec/generated/explain.json | 0 .../spec/generated/field_caps.json | 0 .../spec_definitions}/spec/generated/get.json | 0 .../spec/generated/get_script.json | 0 .../spec/generated/get_script_context.json | 0 .../spec/generated/get_script_languages.json | 0 .../spec/generated/get_source.json | 0 .../spec/generated/index.json | 0 .../spec/generated/indices.analyze.json | 0 .../spec/generated/indices.clear_cache.json | 0 .../spec/generated/indices.clone.json | 0 .../spec/generated/indices.close.json | 0 .../spec/generated/indices.create.json | 0 .../spec/generated/indices.delete.json | 0 .../spec/generated/indices.delete_alias.json | 0 .../generated/indices.delete_template.json | 0 .../spec/generated/indices.exists.json | 0 .../spec/generated/indices.exists_alias.json | 0 .../generated/indices.exists_template.json | 0 .../spec/generated/indices.exists_type.json | 0 .../spec/generated/indices.flush.json | 0 .../spec/generated/indices.flush_synced.json | 0 .../spec/generated/indices.forcemerge.json | 0 .../spec/generated/indices.get.json | 0 .../spec/generated/indices.get_alias.json | 0 .../generated/indices.get_field_mapping.json | 0 .../spec/generated/indices.get_mapping.json | 0 .../spec/generated/indices.get_settings.json | 0 .../spec/generated/indices.get_template.json | 0 .../spec/generated/indices.get_upgrade.json | 0 .../spec/generated/indices.open.json | 0 .../spec/generated/indices.put_alias.json | 0 .../spec/generated/indices.put_mapping.json | 0 .../spec/generated/indices.put_settings.json | 0 .../spec/generated/indices.put_template.json | 0 .../spec/generated/indices.recovery.json | 0 .../spec/generated/indices.refresh.json | 0 .../spec/generated/indices.rollover.json | 0 .../spec/generated/indices.segments.json | 0 .../spec/generated/indices.shard_stores.json | 0 .../spec/generated/indices.shrink.json | 0 .../spec/generated/indices.split.json | 0 .../spec/generated/indices.stats.json | 0 .../generated/indices.update_aliases.json | 0 .../spec/generated/indices.upgrade.json | 0 .../generated/indices.validate_query.json | 0 .../spec/generated/info.json | 0 .../generated/ingest.delete_pipeline.json | 0 .../spec/generated/ingest.get_pipeline.json | 0 .../spec/generated/ingest.processor_grok.json | 0 .../spec/generated/ingest.put_pipeline.json | 0 .../spec/generated/ingest.simulate.json | 0 .../spec/generated/mget.json | 0 .../spec/generated/msearch.json | 0 .../spec/generated/msearch_template.json | 0 .../spec/generated/mtermvectors.json | 0 .../spec/generated/nodes.hot_threads.json | 0 .../spec/generated/nodes.info.json | 0 .../nodes.reload_secure_settings.json | 0 .../spec/generated/nodes.stats.json | 0 .../spec/generated/nodes.usage.json | 0 .../spec/generated/ping.json | 0 .../spec/generated/put_script.json | 0 .../spec/generated/rank_eval.json | 0 .../spec/generated/reindex.json | 0 .../spec/generated/reindex_rethrottle.json | 0 .../generated/render_search_template.json | 0 .../generated/scripts_painless_execute.json | 0 .../spec/generated/scroll.json | 0 .../spec/generated/search.json | 0 .../spec/generated/search_shards.json | 0 .../spec/generated/search_template.json | 0 .../snapshot.cleanup_repository.json | 0 .../spec/generated/snapshot.create.json | 0 .../generated/snapshot.create_repository.json | 0 .../spec/generated/snapshot.delete.json | 0 .../generated/snapshot.delete_repository.json | 0 .../spec/generated/snapshot.get.json | 0 .../generated/snapshot.get_repository.json | 0 .../spec/generated/snapshot.restore.json | 0 .../spec/generated/snapshot.status.json | 0 .../generated/snapshot.verify_repository.json | 0 .../spec/generated/tasks.cancel.json | 0 .../spec/generated/tasks.get.json | 0 .../spec/generated/tasks.list.json | 0 .../spec/generated/termvectors.json | 0 .../spec/generated/update.json | 0 .../spec/generated/update_by_query.json | 0 .../generated/update_by_query_rethrottle.json | 0 .../lib/spec_definitions}/spec/index.js | 0 .../spec/overrides/clear_scroll.json | 0 .../spec/overrides/cluster.health.json | 0 .../spec/overrides/cluster.put_settings.json | 0 .../spec/overrides/cluster.reroute.json | 0 .../spec/overrides/count.json | 0 .../spec/overrides/indices.analyze.json | 0 .../spec/overrides/indices.clone.json | 0 .../spec/overrides/indices.create.json | 0 .../overrides/indices.delete_template.json | 0 .../overrides/indices.exists_template.json | 0 .../overrides/indices.get_field_mapping.json | 0 .../spec/overrides/indices.get_mapping.json | 0 .../spec/overrides/indices.get_template.json | 0 .../spec/overrides/indices.put_alias.json | 0 .../spec/overrides/indices.put_settings.json | 0 .../spec/overrides/indices.put_template.json | 0 .../spec/overrides/indices.rollover.json | 0 .../overrides/indices.update_aliases.json | 0 .../overrides/indices.validate_query.json | 0 .../spec/overrides/snapshot.create.json | 0 .../overrides/snapshot.create_repository.json | 0 .../spec/overrides/snapshot.restore.json | 0 .../console/server/lib/wildcard_matcher.ts} | 12 +- src/plugins/console/server/plugin.ts | 81 +++++++ .../api/console/proxy/create_handler.ts | 217 ++++++++++++++++++ .../server/routes/api/console/proxy/index.ts | 44 ++++ .../api/console/proxy/validation_config.ts | 44 ++++ .../api/console/spec_definitions/index.ts | 48 ++++ src/plugins/console/server/types.ts | 34 +++ x-pack/index.js | 2 - .../plugins/console_extensions/index.js | 47 ---- x-pack/plugins/console_extensions/kibana.json | 8 + .../console_extensions/server/config.ts | 12 + .../console_extensions/server/index.ts | 15 ++ .../console_extensions/server/plugin.ts | 32 +++ .../ccr.delete_auto_follow_pattern.json | 0 .../server}/spec/generated/ccr.follow.json | 0 .../spec/generated/ccr.follow_info.json | 0 .../spec/generated/ccr.follow_stats.json | 0 .../spec/generated/ccr.forget_follower.json | 0 .../ccr.get_auto_follow_pattern.json | 0 .../ccr.pause_auto_follow_pattern.json | 0 .../spec/generated/ccr.pause_follow.json | 0 .../ccr.put_auto_follow_pattern.json | 0 .../ccr.resume_auto_follow_pattern.json | 0 .../spec/generated/ccr.resume_follow.json | 0 .../server}/spec/generated/ccr.stats.json | 0 .../server}/spec/generated/ccr.unfollow.json | 0 .../spec/generated/enrich.delete_policy.json | 0 .../spec/generated/enrich.execute_policy.json | 0 .../spec/generated/enrich.get_policy.json | 0 .../spec/generated/enrich.put_policy.json | 0 .../server}/spec/generated/enrich.stats.json | 0 .../server}/spec/generated/graph.explore.json | 0 .../spec/generated/ilm.delete_lifecycle.json | 0 .../spec/generated/ilm.explain_lifecycle.json | 0 .../spec/generated/ilm.get_lifecycle.json | 0 .../spec/generated/ilm.get_status.json | 0 .../spec/generated/ilm.move_to_step.json | 0 .../spec/generated/ilm.put_lifecycle.json | 0 .../spec/generated/ilm.remove_policy.json | 0 .../server}/spec/generated/ilm.retry.json | 0 .../spec/generated/ilm.set_policy.json | 0 .../server}/spec/generated/ilm.start.json | 0 .../server}/spec/generated/ilm.stop.json | 0 .../spec/generated/indices.freeze.json | 0 .../indices.reload_search_analyzers.json | 0 .../spec/generated/indices.unfreeze.json | 0 .../spec/generated/license.delete.json | 0 .../server}/spec/generated/license.get.json | 0 .../generated/license.get_basic_status.json | 0 .../generated/license.get_trial_status.json | 0 .../server}/spec/generated/license.post.json | 0 .../generated/license.post_start_basic.json | 0 .../generated/license.post_start_trial.json | 0 .../generated/migration.deprecations.json | 0 .../generated/migration.get_assistance.json | 0 .../spec/generated/migration.upgrade.json | 0 .../server}/spec/generated/ml.close_job.json | 0 .../spec/generated/ml.delete_calendar.json | 0 .../generated/ml.delete_calendar_event.json | 0 .../generated/ml.delete_calendar_job.json | 0 .../ml.delete_data_frame_analytics.json | 0 .../spec/generated/ml.delete_datafeed.json | 0 .../generated/ml.delete_expired_data.json | 0 .../spec/generated/ml.delete_filter.json | 0 .../spec/generated/ml.delete_forecast.json | 0 .../server}/spec/generated/ml.delete_job.json | 0 .../generated/ml.delete_model_snapshot.json | 0 .../generated/ml.delete_trained_model.json | 0 .../generated/ml.estimate_memory_usage.json | 0 .../generated/ml.evaluate_data_frame.json | 0 .../ml.explain_data_frame_analytics.json | 0 .../generated/ml.find_file_structure.json | 0 .../server}/spec/generated/ml.flush_job.json | 0 .../server}/spec/generated/ml.forecast.json | 0 .../spec/generated/ml.get_buckets.json | 0 .../generated/ml.get_calendar_events.json | 0 .../spec/generated/ml.get_calendars.json | 0 .../spec/generated/ml.get_categories.json | 0 .../ml.get_data_frame_analytics.json | 0 .../ml.get_data_frame_analytics_stats.json | 0 .../spec/generated/ml.get_datafeed_stats.json | 0 .../spec/generated/ml.get_datafeeds.json | 0 .../spec/generated/ml.get_filters.json | 0 .../spec/generated/ml.get_influencers.json | 0 .../spec/generated/ml.get_job_stats.json | 0 .../server}/spec/generated/ml.get_jobs.json | 0 .../generated/ml.get_model_snapshots.json | 0 .../generated/ml.get_overall_buckets.json | 0 .../spec/generated/ml.get_records.json | 0 .../spec/generated/ml.get_trained_models.json | 0 .../ml.get_trained_models_stats.json | 0 .../server}/spec/generated/ml.info.json | 0 .../server}/spec/generated/ml.open_job.json | 0 .../generated/ml.post_calendar_events.json | 0 .../server}/spec/generated/ml.post_data.json | 0 .../spec/generated/ml.preview_datafeed.json | 0 .../spec/generated/ml.put_calendar.json | 0 .../spec/generated/ml.put_calendar_job.json | 0 .../ml.put_data_frame_analytics.json | 0 .../spec/generated/ml.put_datafeed.json | 0 .../server}/spec/generated/ml.put_filter.json | 0 .../server}/spec/generated/ml.put_job.json | 0 .../spec/generated/ml.put_trained_model.json | 0 .../generated/ml.revert_model_snapshot.json | 0 .../spec/generated/ml.set_upgrade_mode.json | 0 .../ml.start_data_frame_analytics.json | 0 .../spec/generated/ml.start_datafeed.json | 0 .../ml.stop_data_frame_analytics.json | 0 .../spec/generated/ml.stop_datafeed.json | 0 .../spec/generated/ml.update_datafeed.json | 0 .../spec/generated/ml.update_filter.json | 0 .../server}/spec/generated/ml.update_job.json | 0 .../generated/ml.update_model_snapshot.json | 0 .../server}/spec/generated/ml.upgrade.json | 0 .../server}/spec/generated/ml.validate.json | 0 .../spec/generated/ml.validate_detector.json | 0 .../spec/generated/monitoring.bulk.json | 0 .../spec/generated/rollup.delete_job.json | 0 .../spec/generated/rollup.get_jobs.json | 0 .../generated/rollup.get_rollup_caps.json | 0 .../rollup.get_rollup_index_caps.json | 0 .../spec/generated/rollup.put_job.json | 0 .../spec/generated/rollup.rollup_search.json | 0 .../spec/generated/rollup.start_job.json | 0 .../spec/generated/rollup.stop_job.json | 0 .../spec/generated/security.authenticate.json | 0 .../generated/security.change_password.json | 0 .../security.clear_cached_realms.json | 0 .../security.clear_cached_roles.json | 0 .../generated/security.create_api_key.json | 0 .../generated/security.delete_privileges.json | 0 .../spec/generated/security.delete_role.json | 0 .../security.delete_role_mapping.json | 0 .../spec/generated/security.delete_user.json | 0 .../spec/generated/security.disable_user.json | 0 .../spec/generated/security.enable_user.json | 0 .../spec/generated/security.get_api_key.json | 0 .../security.get_builtin_privileges.json | 0 .../generated/security.get_privileges.json | 0 .../spec/generated/security.get_role.json | 0 .../generated/security.get_role_mapping.json | 0 .../spec/generated/security.get_token.json | 0 .../spec/generated/security.get_user.json | 0 .../security.get_user_privileges.json | 0 .../generated/security.has_privileges.json | 0 .../security.invalidate_api_key.json | 0 .../generated/security.invalidate_token.json | 0 .../generated/security.put_privileges.json | 0 .../spec/generated/security.put_role.json | 0 .../generated/security.put_role_mapping.json | 0 .../spec/generated/security.put_user.json | 0 .../spec/generated/slm.delete_lifecycle.json | 0 .../spec/generated/slm.execute_lifecycle.json | 0 .../spec/generated/slm.execute_retention.json | 0 .../spec/generated/slm.get_lifecycle.json | 0 .../server}/spec/generated/slm.get_stats.json | 0 .../spec/generated/slm.get_status.json | 0 .../spec/generated/slm.put_lifecycle.json | 0 .../server}/spec/generated/slm.start.json | 0 .../server}/spec/generated/slm.stop.json | 0 .../spec/generated/sql.clear_cursor.json | 0 .../server}/spec/generated/sql.query.json | 0 .../server}/spec/generated/sql.translate.json | 0 .../spec/generated/ssl.certificates.json | 0 .../generated/transform.delete_transform.json | 0 .../generated/transform.get_transform.json | 0 .../transform.get_transform_stats.json | 0 .../transform.preview_transform.json | 0 .../generated/transform.put_transform.json | 0 .../generated/transform.start_transform.json | 0 .../generated/transform.stop_transform.json | 0 .../generated/transform.update_transform.json | 0 .../spec/generated/watcher.ack_watch.json | 0 .../generated/watcher.activate_watch.json | 0 .../generated/watcher.deactivate_watch.json | 0 .../spec/generated/watcher.delete_watch.json | 0 .../spec/generated/watcher.execute_watch.json | 0 .../spec/generated/watcher.get_watch.json | 0 .../spec/generated/watcher.put_watch.json | 0 .../server}/spec/generated/watcher.start.json | 0 .../server}/spec/generated/watcher.stats.json | 0 .../server}/spec/generated/watcher.stop.json | 0 .../server}/spec/generated/xpack.info.json | 0 .../generated/xpack.ssl.certificates.json | 0 .../server}/spec/generated/xpack.usage.json | 0 .../server/spec/ingest/index.ts} | 0 .../server}/spec/overrides/ccr.follow.json | 0 .../spec/overrides/ccr.forget_follower.json | 0 .../ccr.put_auto_follow_pattern.json | 0 .../spec/overrides/ccr.resume_follow.json | 0 .../spec/overrides/enrich.put_policy.json | 0 .../spec/overrides/ilm.move_to_step.json | 0 .../spec/overrides/ilm.put_lifecycle.json | 0 .../overrides/ml.estimate_memory_usage.json | 0 .../overrides/ml.evaluate_data_frame.json | 0 .../ml.explain_data_frame_analytics.json | 0 .../spec/overrides/ml.get_buckets.json | 0 .../overrides/ml.get_calendar_events.json | 0 .../spec/overrides/ml.get_calendars.json | 0 .../spec/overrides/ml.get_categories.json | 0 .../spec/overrides/ml.get_influencers.json | 0 .../overrides/ml.get_model_snapshots.json | 0 .../overrides/ml.get_overall_buckets.json | 0 .../spec/overrides/ml.get_records.json | 0 .../overrides/ml.post_calendar_events.json | 0 .../spec/overrides/ml.put_calendar.json | 0 .../ml.put_data_frame_analytics.json | 0 .../spec/overrides/ml.put_datafeed.json | 0 .../server}/spec/overrides/ml.put_job.json | 0 .../spec/overrides/ml.put_trained_model.json | 0 .../overrides/ml.revert_model_snapshot.json | 0 .../spec/overrides/ml.update_datafeed.json | 0 .../server}/spec/overrides/ml.update_job.json | 0 .../overrides/ml.update_model_snapshot.json | 0 .../spec/overrides/security.authenticate.json | 0 .../overrides/security.change_password.json | 0 .../overrides/security.create_api_key.json | 0 .../overrides/security.delete_privileges.json | 0 .../spec/overrides/security.get_token.json | 0 .../overrides/security.has_privileges.json | 0 .../security.invalidate_api_key.json | 0 .../overrides/security.invalidate_token.json | 0 .../overrides/security.put_privileges.json | 0 .../spec/overrides/security.put_role.json | 0 .../overrides/security.put_role_mapping.json | 0 .../spec/overrides/security.put_user.json | 0 .../spec/overrides/slm.put_lifecycle.json | 0 .../server}/spec/overrides/slm.start.json | 0 .../server}/spec/overrides/slm.stop.json | 0 .../server}/spec/overrides/sql.query.json | 0 .../transform.get_transform_stats.json | 0 .../transform.preview_transform.json | 0 .../overrides/transform.put_transform.json | 0 .../overrides/transform.stop_transform.json | 0 .../overrides/transform.update_transform.json | 0 .../spec/overrides/xpack.graph.explore.json | 0 .../server}/spec/overrides/xpack.info.json | 0 .../spec/overrides/xpack.license.post.json | 0 .../overrides/xpack.rollup.delete_job.json | 0 .../spec/overrides/xpack.rollup.put_job.json | 0 .../overrides/xpack.rollup.rollup_search.json | 0 .../xpack.security.authenticate.json | 0 .../xpack.security.change_password.json | 0 .../overrides/xpack.security.get_token.json | 0 .../xpack.security.invalidate_token.json | 0 .../overrides/xpack.security.put_role.json | 0 .../xpack.security.put_role_mapping.json | 0 .../overrides/xpack.security.put_user.json | 0 .../xpack.watcher.execute_watch.json | 0 .../overrides/xpack.watcher.put_watch.json | 0 613 files changed, 1345 insertions(+), 1081 deletions(-) delete mode 100644 src/legacy/core_plugins/console/__tests__/index.js delete mode 100644 src/legacy/core_plugins/console/index.ts delete mode 100644 src/legacy/core_plugins/console/package.json delete mode 100644 src/legacy/core_plugins/console/public/legacy.ts delete mode 100644 src/legacy/core_plugins/console/server/__tests__/proxy_route/headers.js delete mode 100644 src/legacy/core_plugins/console/server/__tests__/proxy_route/params.js delete mode 100644 src/legacy/core_plugins/console/server/__tests__/proxy_route/query_string.js delete mode 100644 src/legacy/core_plugins/console/server/proxy_route.ts create mode 100644 src/legacy/core_plugins/console_legacy/index.ts create mode 100644 src/legacy/core_plugins/console_legacy/package.json rename src/legacy/core_plugins/{console/public/np_ready/application => console_legacy/public}/styles/_app.scss (100%) rename src/legacy/core_plugins/{console/public/np_ready/application => console_legacy/public}/styles/components/_help.scss (100%) rename src/legacy/core_plugins/{console/public/np_ready/application => console_legacy/public}/styles/components/_history.scss (100%) rename src/legacy/core_plugins/{console/public/np_ready/application => console_legacy/public}/styles/components/_index.scss (100%) rename src/legacy/core_plugins/{console/public/np_ready/application => console_legacy/public}/styles/index.scss (100%) rename src/{legacy/core_plugins => plugins}/console/common/text_object.ts (100%) create mode 100644 src/plugins/console/common/types/index.ts rename src/{legacy/core_plugins/console/common/types.ts => plugins/console/common/types/models.ts} (97%) create mode 100644 src/plugins/console/common/types/plugin_config.ts rename src/{legacy/core_plugins/console/public => plugins/console}/kibana.json (73%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/console_menu.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/editor_content_spinner.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/editor_example.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/help_panel.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/settings_modal.tsx (98%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/something_went_wrong_callout.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/top_nav_menu.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/components/welcome_panel.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/constants/help_example.txt (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/console_history/console_history.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/console_history/history_viewer.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/console_history/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/editor.tsx (96%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/apply_editor_settings.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/editor.test.mock.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/editor.test.tsx (99%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/editor.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/editor_output.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/console_menu_actions.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/subscribe_console_resize_checker.ts (93%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/main/get_top_nav.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/main/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/main/main.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/containers/settings.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/create_use_context.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/editor_context/editor_context.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/editor_context/editor_registry.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/editor_context/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/request_context.tsx (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/contexts/services_context.tsx (96%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/factories/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/factories/token_iterator.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_data_init/data_migration.ts (95%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_data_init/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_data_init/use_data_init.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_restore_request_from_history/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_restore_request_from_history/restore_request_from_history.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_save_current_text_object.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_send_current_request_to_es/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_send_current_request_to_es/send_request_to_es.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_send_current_request_to_es/track.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/hooks/use_set_input_editor.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/index.tsx (81%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/logo.svg (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/__tests__/input_tokenization.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/__tests__/output_tokenization.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/create.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/create_readonly.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/legacy_core_editor.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/elasticsearch_sql_highlight_rules.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/input.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/input_highlight_rules.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/output.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/output_highlight_rules.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/script.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/script_highlight_rules.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/worker/index.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/worker/worker.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/mode/x_json_highlight_rules.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/smart_resize.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/legacy_core_editor/theme_sense_dark.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/__tests__/editor_input1.txt (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/__tests__/integration.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/__tests__/sense_editor.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/create.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/curl.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/sense_editor.test.mocks.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/models/sense_editor/sense_editor.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/stores/editor.ts (96%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/application/stores/request.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/index.ts (85%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/ace_token_provider/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/ace_token_provider/token_provider.test.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/ace_token_provider/token_provider.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/__tests__/url_autocomplete.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/__tests__/url_params.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/autocomplete.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/body_completer.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/accept_endpoint_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/conditional_proxy.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/constant_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/field_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/full_request_component.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/global_only_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/id_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/index.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/index_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/list_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/object_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/shared_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/simple_param_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/template_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/type_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/url_pattern_matcher.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/components/username_autocomplete_component.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/engine.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/get_endpoint_from_position.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/autocomplete/url_params.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/curl_parsing/__tests__/curl_parsing.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/curl_parsing/__tests__/curl_parsing.txt (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/curl_parsing/curl.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/es/__tests__/content_type.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/es/es.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/kb/__tests__/kb.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/kb/api.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/kb/index.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/kb/kb.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/local_storage_object_client/create.ts (88%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/local_storage_object_client/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/local_storage_object_client/local_storage_object_client.ts (96%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/mappings/__tests__/mapping.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/mappings/mappings.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/row_parser.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/token_iterator/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/token_iterator/token_iterator.test.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/token_iterator/token_iterator.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/utils/__tests__/utils.test.js (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/utils/__tests__/utils_string_collapsing.txt (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/utils/__tests__/utils_string_expanding.txt (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/lib/utils/utils.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/plugin.ts (58%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/services/history.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/services/index.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/services/settings.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/services/storage.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/services/tracker.ts (62%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/types/common.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/types/core_editor.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/types/index.ts (95%) create mode 100644 src/plugins/console/public/types/plugin_dependencies.ts rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/types/token.ts (100%) rename src/{legacy/core_plugins/console/public/np_ready => plugins/console/public}/types/tokens_provider.ts (100%) rename src/{legacy/core_plugins => plugins}/console/server/__tests__/elasticsearch_proxy_config.js (98%) rename src/{legacy/core_plugins => plugins}/console/server/__tests__/proxy_config.js (99%) rename src/{legacy/core_plugins => plugins}/console/server/__tests__/proxy_config_collection.js (98%) rename src/{legacy/core_plugins/console/server/__tests__/proxy_route/body.js => plugins/console/server/__tests__/proxy_route/body.test.ts} (63%) create mode 100644 src/plugins/console/server/__tests__/proxy_route/headers.test.ts create mode 100644 src/plugins/console/server/__tests__/proxy_route/mocks.ts create mode 100644 src/plugins/console/server/__tests__/proxy_route/params.test.ts create mode 100644 src/plugins/console/server/__tests__/proxy_route/query_string.test.ts create mode 100644 src/plugins/console/server/__tests__/proxy_route/route_validation.test.ts rename src/{legacy/core_plugins/console/server/__tests__/proxy_route/stubs.js => plugins/console/server/__tests__/proxy_route/stubs.ts} (65%) rename src/{legacy/core_plugins => plugins}/console/server/__tests__/set_headers.js (97%) rename src/{legacy/core_plugins => plugins}/console/server/__tests__/wildcard_matcher.js (98%) create mode 100644 src/plugins/console/server/config.ts create mode 100644 src/plugins/console/server/index.ts rename src/{legacy/core_plugins/console/server => plugins/console/server/lib}/elasticsearch_proxy_config.ts (94%) rename src/{legacy/core_plugins/console/server/index.js => plugins/console/server/lib/index.ts} (80%) rename src/{legacy/core_plugins/console/server/proxy_config.js => plugins/console/server/lib/proxy_config.ts} (80%) rename src/{legacy/core_plugins/console/server/proxy_config_collection.js => plugins/console/server/lib/proxy_config_collection.ts} (83%) rename src/{legacy/core_plugins/console/server/request.test.ts => plugins/console/server/lib/proxy_request.test.ts} (96%) rename src/{legacy/core_plugins/console/server/request.ts => plugins/console/server/lib/proxy_request.ts} (99%) rename src/{legacy/core_plugins/console/server/set_headers.js => plugins/console/server/lib/set_headers.ts} (94%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/api.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/aggregations.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/aliases.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/document.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/filter.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/globals.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/ingest.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/mappings.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/query/dsl.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/query/index.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/query/templates.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/reindex.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/es_6_0/search.js (100%) create mode 100644 src/plugins/console/server/lib/spec_definitions/index.d.ts create mode 100644 src/plugins/console/server/lib/spec_definitions/index.js rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/server.js (91%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/server.test.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/.eslintrc (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/_common.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/bulk.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.aliases.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.allocation.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.count.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.fielddata.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.health.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.help.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.indices.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.master.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.nodeattrs.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.nodes.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.pending_tasks.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.plugins.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.recovery.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.repositories.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.segments.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.shards.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.snapshots.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.tasks.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.templates.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cat.thread_pool.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/clear_scroll.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.allocation_explain.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.get_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.health.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.pending_tasks.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.put_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.remote_info.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.reroute.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.state.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/cluster.stats.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/count.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/create.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/delete.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/delete_by_query.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/delete_by_query_rethrottle.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/delete_script.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/exists.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/exists_source.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/explain.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/field_caps.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/get.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/get_script.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/get_script_context.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/get_script_languages.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/get_source.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/index.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.analyze.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.clear_cache.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.clone.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.close.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.create.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.delete.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.delete_alias.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.delete_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.exists.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.exists_alias.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.exists_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.exists_type.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.flush.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.flush_synced.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.forcemerge.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_alias.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_field_mapping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_mapping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.get_upgrade.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.open.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.put_alias.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.put_mapping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.put_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.put_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.recovery.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.refresh.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.rollover.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.segments.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.shard_stores.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.shrink.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.split.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.stats.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.update_aliases.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.upgrade.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/indices.validate_query.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/info.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ingest.delete_pipeline.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ingest.get_pipeline.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ingest.processor_grok.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ingest.put_pipeline.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ingest.simulate.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/mget.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/msearch.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/msearch_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/mtermvectors.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/nodes.hot_threads.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/nodes.info.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/nodes.reload_secure_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/nodes.stats.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/nodes.usage.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/ping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/put_script.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/rank_eval.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/reindex.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/reindex_rethrottle.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/render_search_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/scripts_painless_execute.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/scroll.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/search.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/search_shards.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/search_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.cleanup_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.create.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.create_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.delete.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.delete_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.get.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.get_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.restore.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.status.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/snapshot.verify_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/tasks.cancel.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/tasks.get.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/tasks.list.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/termvectors.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/update.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/update_by_query.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/generated/update_by_query_rethrottle.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/index.js (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/clear_scroll.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/cluster.health.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/cluster.put_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/cluster.reroute.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/count.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.analyze.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.clone.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.create.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.delete_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.exists_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.get_field_mapping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.get_mapping.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.get_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.put_alias.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.put_settings.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.put_template.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.rollover.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.update_aliases.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/indices.validate_query.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/snapshot.create.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/snapshot.create_repository.json (100%) rename src/{legacy/core_plugins/console/server/api_server => plugins/console/server/lib/spec_definitions}/spec/overrides/snapshot.restore.json (100%) rename src/{legacy/core_plugins/console/server/wildcard_matcher.js => plugins/console/server/lib/wildcard_matcher.ts} (81%) create mode 100644 src/plugins/console/server/plugin.ts create mode 100644 src/plugins/console/server/routes/api/console/proxy/create_handler.ts create mode 100644 src/plugins/console/server/routes/api/console/proxy/index.ts create mode 100644 src/plugins/console/server/routes/api/console/proxy/validation_config.ts create mode 100644 src/plugins/console/server/routes/api/console/spec_definitions/index.ts create mode 100644 src/plugins/console/server/types.ts delete mode 100644 x-pack/legacy/plugins/console_extensions/index.js create mode 100644 x-pack/plugins/console_extensions/kibana.json create mode 100644 x-pack/plugins/console_extensions/server/config.ts create mode 100644 x-pack/plugins/console_extensions/server/index.ts create mode 100644 x-pack/plugins/console_extensions/server/plugin.ts rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.delete_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.follow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.follow_info.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.follow_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.forget_follower.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.get_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.pause_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.pause_follow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.put_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.resume_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.resume_follow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ccr.unfollow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/enrich.delete_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/enrich.execute_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/enrich.get_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/enrich.put_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/enrich.stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/graph.explore.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.delete_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.explain_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.get_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.get_status.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.move_to_step.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.put_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.remove_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.retry.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.set_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.start.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ilm.stop.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/indices.freeze.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/indices.reload_search_analyzers.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/indices.unfreeze.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.delete.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.get.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.get_basic_status.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.get_trial_status.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.post.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.post_start_basic.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/license.post_start_trial.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/migration.deprecations.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/migration.get_assistance.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/migration.upgrade.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.close_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_calendar.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_calendar_event.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_calendar_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_expired_data.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_filter.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_forecast.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_model_snapshot.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.delete_trained_model.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.estimate_memory_usage.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.evaluate_data_frame.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.explain_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.find_file_structure.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.flush_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.forecast.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_buckets.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_calendar_events.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_calendars.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_categories.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_data_frame_analytics_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_datafeed_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_datafeeds.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_filters.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_influencers.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_job_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_jobs.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_model_snapshots.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_overall_buckets.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_records.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_trained_models.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.get_trained_models_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.info.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.open_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.post_calendar_events.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.post_data.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.preview_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_calendar.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_calendar_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_filter.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.put_trained_model.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.revert_model_snapshot.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.set_upgrade_mode.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.start_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.start_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.stop_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.stop_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.update_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.update_filter.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.update_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.update_model_snapshot.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.upgrade.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.validate.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ml.validate_detector.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/monitoring.bulk.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.delete_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.get_jobs.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.get_rollup_caps.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.get_rollup_index_caps.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.put_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.rollup_search.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.start_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/rollup.stop_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.authenticate.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.change_password.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.clear_cached_realms.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.clear_cached_roles.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.create_api_key.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.delete_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.delete_role.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.delete_role_mapping.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.delete_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.disable_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.enable_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_api_key.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_builtin_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_role.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_role_mapping.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.get_user_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.has_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.invalidate_api_key.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.invalidate_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.put_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.put_role.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.put_role_mapping.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/security.put_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.delete_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.execute_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.execute_retention.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.get_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.get_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.get_status.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.put_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.start.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/slm.stop.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/sql.clear_cursor.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/sql.query.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/sql.translate.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/ssl.certificates.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.delete_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.get_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.get_transform_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.preview_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.put_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.start_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.stop_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/transform.update_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.ack_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.activate_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.deactivate_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.delete_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.execute_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.get_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.put_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.start.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/watcher.stop.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/xpack.info.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/xpack.ssl.certificates.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/generated/xpack.usage.json (100%) rename x-pack/{legacy/plugins/console_extensions/spec/ingest/index.js => plugins/console_extensions/server/spec/ingest/index.ts} (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ccr.follow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ccr.forget_follower.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ccr.put_auto_follow_pattern.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ccr.resume_follow.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/enrich.put_policy.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ilm.move_to_step.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ilm.put_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.estimate_memory_usage.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.evaluate_data_frame.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.explain_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_buckets.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_calendar_events.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_calendars.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_categories.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_influencers.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_model_snapshots.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_overall_buckets.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.get_records.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.post_calendar_events.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.put_calendar.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.put_data_frame_analytics.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.put_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.put_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.put_trained_model.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.revert_model_snapshot.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.update_datafeed.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.update_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/ml.update_model_snapshot.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.authenticate.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.change_password.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.create_api_key.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.delete_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.get_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.has_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.invalidate_api_key.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.invalidate_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.put_privileges.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.put_role.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.put_role_mapping.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/security.put_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/slm.put_lifecycle.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/slm.start.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/slm.stop.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/sql.query.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/transform.get_transform_stats.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/transform.preview_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/transform.put_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/transform.stop_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/transform.update_transform.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.graph.explore.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.info.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.license.post.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.rollup.delete_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.rollup.put_job.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.rollup.rollup_search.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.authenticate.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.change_password.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.get_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.invalidate_token.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.put_role.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.put_role_mapping.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.security.put_user.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.watcher.execute_watch.json (100%) rename x-pack/{legacy/plugins/console_extensions => plugins/console_extensions/server}/spec/overrides/xpack.watcher.put_watch.json (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index eff8c58a48b0d4..37ca1ff7bbdec6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -150,9 +150,9 @@ **/*.scss @elastic/kibana-design # Elasticsearch UI -/src/legacy/core_plugins/console/ @elastic/es-ui +/src/plugins/console/ @elastic/es-ui /src/plugins/es_ui_shared/ @elastic/es-ui -/x-pack/legacy/plugins/console_extensions/ @elastic/es-ui +/x-pack/plugins/console_extensions/ @elastic/es-ui /x-pack/legacy/plugins/cross_cluster_replication/ @elastic/es-ui /x-pack/legacy/plugins/index_lifecycle_management/ @elastic/es-ui /x-pack/legacy/plugins/index_management/ @elastic/es-ui diff --git a/.i18nrc.json b/.i18nrc.json index af21f3426d75ec..98c36b43e5d8fa 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -1,7 +1,7 @@ { "paths": { "common.ui": "src/legacy/ui", - "console": "src/legacy/core_plugins/console", + "console": "src/plugins/console", "core": "src/core", "dashboardEmbeddableContainer": "src/plugins/dashboard_embeddable_container", "data": [ diff --git a/src/core/server/http/router/response_adapter.ts b/src/core/server/http/router/response_adapter.ts index e5dabc99f44426..948b4596e26588 100644 --- a/src/core/server/http/router/response_adapter.ts +++ b/src/core/server/http/router/response_adapter.ts @@ -19,6 +19,7 @@ import { ResponseObject as HapiResponseObject, ResponseToolkit as HapiResponseToolkit } from 'hapi'; import typeDetect from 'type-detect'; import Boom from 'boom'; +import * as stream from 'stream'; import { HttpResponsePayload, @@ -112,8 +113,18 @@ export class HapiResponseAdapter { return response; } - private toError(kibanaResponse: KibanaResponse) { + private toError(kibanaResponse: KibanaResponse) { const { payload } = kibanaResponse; + + // Special case for when we are proxying requests and want to enable streaming back error responses opaquely. + if (Buffer.isBuffer(payload) || payload instanceof stream.Readable) { + const response = this.responseToolkit + .response(kibanaResponse.payload) + .code(kibanaResponse.status); + setHeaders(response, kibanaResponse.options.headers); + return response; + } + // we use for BWC with Boom payload for error responses - {error: string, message: string, statusCode: string} const error = new Boom('', { statusCode: kibanaResponse.status, diff --git a/src/legacy/core_plugins/console/__tests__/index.js b/src/legacy/core_plugins/console/__tests__/index.js deleted file mode 100644 index c811bb3f89bbaf..00000000000000 --- a/src/legacy/core_plugins/console/__tests__/index.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Deprecations } from '../../../deprecation'; -import expect from '@kbn/expect'; -import index from '../index'; -import { noop } from 'lodash'; -import sinon from 'sinon'; - -describe('plugins/console', function() { - describe('#deprecate()', function() { - let transformDeprecations; - - before(function() { - const Plugin = function(options) { - this.deprecations = options.deprecations; - }; - - const plugin = index({ Plugin }); - - const deprecations = plugin.deprecations(Deprecations); - transformDeprecations = (settings, log = noop) => { - deprecations.forEach(deprecation => deprecation(settings, log)); - }; - }); - - describe('proxyConfig', function() { - it('leaves the proxyConfig settings', function() { - const proxyConfigOne = {}; - const proxyConfigTwo = {}; - const settings = { - proxyConfig: [proxyConfigOne, proxyConfigTwo], - }; - - transformDeprecations(settings); - expect(settings.proxyConfig[0]).to.be(proxyConfigOne); - expect(settings.proxyConfig[1]).to.be(proxyConfigTwo); - }); - - it('logs a warning when proxyConfig is specified', function() { - const settings = { - proxyConfig: [], - }; - - const log = sinon.spy(); - transformDeprecations(settings, log); - expect(log.calledOnce).to.be(true); - }); - - it(`doesn't log a warning when proxyConfig isn't specified`, function() { - const settings = {}; - - const log = sinon.spy(); - transformDeprecations(settings, log); - expect(log.called).to.be(false); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/console/index.ts b/src/legacy/core_plugins/console/index.ts deleted file mode 100644 index cec6d0a4219ae1..00000000000000 --- a/src/legacy/core_plugins/console/index.ts +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import Boom from 'boom'; -import { first } from 'rxjs/operators'; -import { resolve, join } from 'path'; -import url from 'url'; -import { has, isEmpty, head, pick } from 'lodash'; - -// @ts-ignore -import { addProcessorDefinition } from './server/api_server/es_6_0/ingest'; -// @ts-ignore -import { resolveApi } from './server/api_server/server'; -// @ts-ignore -import { addExtensionSpecFilePath } from './server/api_server/spec'; -// @ts-ignore -import { setHeaders } from './server/set_headers'; -// @ts-ignore -import { ProxyConfigCollection, getElasticsearchProxyConfig, createProxyRoute } from './server'; - -function filterHeaders(originalHeaders: any, headersToKeep: any) { - const normalizeHeader = function(header: any) { - if (!header) { - return ''; - } - header = header.toString(); - return header.trim().toLowerCase(); - }; - - // Normalize list of headers we want to allow in upstream request - const headersToKeepNormalized = headersToKeep.map(normalizeHeader); - - return pick(originalHeaders, headersToKeepNormalized); -} - -// eslint-disable-next-line -export default function(kibana: any) { - const npSrc = resolve(__dirname, 'public/np_ready'); - - let defaultVars: any; - return new kibana.Plugin({ - id: 'console', - require: ['elasticsearch'], - - config(Joi: any) { - return Joi.object({ - enabled: Joi.boolean().default(true), - proxyFilter: Joi.array() - .items(Joi.string()) - .single() - .default(['.*']), - ssl: Joi.object({ - verify: Joi.boolean(), - }).default(), - proxyConfig: Joi.array() - .items( - Joi.object().keys({ - match: Joi.object().keys({ - protocol: Joi.string().default('*'), - host: Joi.string().default('*'), - port: Joi.string().default('*'), - path: Joi.string().default('*'), - }), - - timeout: Joi.number(), - ssl: Joi.object() - .keys({ - verify: Joi.boolean(), - ca: Joi.array() - .single() - .items(Joi.string()), - cert: Joi.string(), - key: Joi.string(), - }) - .default(), - }) - ) - .default(), - }).default(); - }, - - deprecations() { - return [ - (settings: any, log: any) => { - if (has(settings, 'proxyConfig')) { - log( - 'Config key "proxyConfig" is deprecated. Configuration can be inferred from the "elasticsearch" settings' - ); - } - }, - ]; - }, - - uiCapabilities() { - return { - dev_tools: { - show: true, - save: true, - }, - }; - }, - - async init(server: any, options: any) { - server.expose('addExtensionSpecFilePath', addExtensionSpecFilePath); - server.expose('addProcessorDefinition', addProcessorDefinition); - - if (options.ssl && options.ssl.verify) { - throw new Error('sense.ssl.verify is no longer supported.'); - } - - const config = server.config(); - const legacyEsConfig = await server.newPlatform.__internals.elasticsearch.legacy.config$ - .pipe(first()) - .toPromise(); - const proxyConfigCollection = new ProxyConfigCollection(options.proxyConfig); - const proxyPathFilters = options.proxyFilter.map((str: string) => new RegExp(str)); - - defaultVars = { - elasticsearchUrl: url.format( - Object.assign(url.parse(head(legacyEsConfig.hosts)), { auth: false }) - ), - }; - - server.route( - createProxyRoute({ - hosts: legacyEsConfig.hosts, - pathFilters: proxyPathFilters, - getConfigForReq(req: any, uri: any) { - const filteredHeaders = filterHeaders( - req.headers, - legacyEsConfig.requestHeadersWhitelist - ); - const headers = setHeaders(filteredHeaders, legacyEsConfig.customHeaders); - - if (!isEmpty(config.get('console.proxyConfig'))) { - return { - ...proxyConfigCollection.configForUri(uri), - headers, - }; - } - - return { - ...getElasticsearchProxyConfig(legacyEsConfig), - headers, - }; - }, - }) - ); - - server.route({ - path: '/api/console/api_server', - method: ['GET', 'POST'], - handler(req: any, h: any) { - const { sense_version: version, apis } = req.query; - if (!apis) { - throw Boom.badRequest('"apis" is a required param.'); - } - - return resolveApi(version, apis.split(','), h); - }, - }); - }, - - uiExports: { - devTools: [resolve(__dirname, 'public/legacy')], - styleSheetPaths: resolve(npSrc, 'application/styles/index.scss'), - injectDefaultVars: () => defaultVars, - noParse: [join(npSrc, 'application/models/legacy_core_editor/mode/worker/worker.js')], - }, - } as any); -} diff --git a/src/legacy/core_plugins/console/package.json b/src/legacy/core_plugins/console/package.json deleted file mode 100644 index 84ebcb95889c7f..00000000000000 --- a/src/legacy/core_plugins/console/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "author": "Boaz Leskes ", - "contributors": [ - "Spencer Alger " - ], - "name": "console", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/console/public/legacy.ts b/src/legacy/core_plugins/console/public/legacy.ts deleted file mode 100644 index d151a27d27e5cc..00000000000000 --- a/src/legacy/core_plugins/console/public/legacy.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { npSetup, npStart } from 'ui/new_platform'; -import { I18nContext } from 'ui/i18n'; -import chrome from 'ui/chrome'; -import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; - -import { plugin } from './np_ready'; -import { DevToolsSetup } from '../../../../plugins/dev_tools/public'; -import { HomePublicPluginSetup } from '../../../../plugins/home/public'; -import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public'; - -export interface XPluginSet { - usageCollection: UsageCollectionSetup; - dev_tools: DevToolsSetup; - home: HomePublicPluginSetup; - __LEGACY: { - I18nContext: any; - elasticsearchUrl: string; - category: FeatureCatalogueCategory; - }; -} - -const pluginInstance = plugin({} as any); - -(async () => { - await pluginInstance.setup(npSetup.core, { - ...npSetup.plugins, - __LEGACY: { - elasticsearchUrl: chrome.getInjected('elasticsearchUrl'), - I18nContext, - category: FeatureCatalogueCategory.ADMIN, - }, - }); - await pluginInstance.start(npStart.core); -})(); diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_route/headers.js b/src/legacy/core_plugins/console/server/__tests__/proxy_route/headers.js deleted file mode 100644 index 3a8233775f9b72..00000000000000 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_route/headers.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { request } from 'http'; - -import sinon from 'sinon'; -import expect from '@kbn/expect'; -import { Server } from 'hapi'; -import * as requestModule from '../../request'; - -import { createProxyRoute } from '../../'; - -import { createResponseStub } from './stubs'; - -describe('Console Proxy Route', () => { - const sandbox = sinon.createSandbox(); - const teardowns = []; - let setup; - - beforeEach(() => { - sandbox.stub(requestModule, 'sendRequest').callsFake(createResponseStub()); - - setup = () => { - const server = new Server(); - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - }) - ); - - teardowns.push(() => server.stop()); - - return { server }; - }; - }); - - afterEach(async () => { - sandbox.restore(); - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - describe('headers', function() { - this.timeout(Infinity); - - it('forwards the remote header info', async () => { - const { server } = setup(); - await server.start(); - - const resp = await new Promise(resolve => { - request( - { - protocol: server.info.protocol + ':', - host: server.info.address, - port: server.info.port, - method: 'POST', - path: '/api/console/proxy?method=GET&path=/', - }, - resolve - ).end(); - }); - - resp.destroy(); - - sinon.assert.calledOnce(requestModule.sendRequest); - const { headers } = requestModule.sendRequest.getCall(0).args[0]; - expect(headers) - .to.have.property('x-forwarded-for') - .and.not.be(''); - expect(headers) - .to.have.property('x-forwarded-port') - .and.not.be(''); - expect(headers) - .to.have.property('x-forwarded-proto') - .and.not.be(''); - expect(headers) - .to.have.property('x-forwarded-host') - .and.not.be(''); - }); - }); -}); diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_route/params.js b/src/legacy/core_plugins/console/server/__tests__/proxy_route/params.js deleted file mode 100644 index 2cf09f96e7b729..00000000000000 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_route/params.js +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Agent } from 'http'; - -import sinon from 'sinon'; -import * as requestModule from '../../request'; -import expect from '@kbn/expect'; -import { Server } from 'hapi'; - -import { createProxyRoute } from '../../'; - -import { createResponseStub } from './stubs'; - -describe('Console Proxy Route', () => { - const sandbox = sinon.createSandbox(); - const teardowns = []; - let setup; - - beforeEach(() => { - sandbox.stub(requestModule, 'sendRequest').callsFake(createResponseStub()); - - setup = () => { - const server = new Server(); - teardowns.push(() => server.stop()); - return { server }; - }; - }); - - afterEach(async () => { - sandbox.restore(); - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - describe('params', () => { - describe('pathFilters', () => { - describe('no matches', () => { - it('rejects with 403', async () => { - const { server } = setup(); - server.route( - createProxyRoute({ - pathFilters: [/^\/foo\//, /^\/bar\//], - }) - ); - - const { statusCode } = await server.inject({ - method: 'POST', - url: '/api/console/proxy?method=GET&path=/baz/id', - }); - - expect(statusCode).to.be(403); - }); - }); - describe('one match', () => { - it('allows the request', async () => { - const { server } = setup(); - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - pathFilters: [/^\/foo\//, /^\/bar\//], - }) - ); - - const { statusCode } = await server.inject({ - method: 'POST', - url: '/api/console/proxy?method=GET&path=/foo/id', - }); - - expect(statusCode).to.be(200); - sinon.assert.calledOnce(requestModule.sendRequest); - }); - }); - describe('all match', () => { - it('allows the request', async () => { - const { server } = setup(); - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - pathFilters: [/^\/foo\//, /^\/bar\//], - }) - ); - - const { statusCode } = await server.inject({ - method: 'POST', - url: '/api/console/proxy?method=GET&path=/foo/id', - }); - - expect(statusCode).to.be(200); - sinon.assert.calledOnce(requestModule.sendRequest); - }); - }); - }); - - describe('getConfigForReq()', () => { - it('passes the request and targeted uri', async () => { - const { server } = setup(); - - const getConfigForReq = sinon.stub().returns({}); - - server.route(createProxyRoute({ hosts: ['http://localhost:9200'], getConfigForReq })); - await server.inject({ - method: 'POST', - url: '/api/console/proxy?method=HEAD&path=/index/id', - }); - - sinon.assert.calledOnce(getConfigForReq); - const args = getConfigForReq.getCall(0).args; - expect(args[0]).to.have.property('path', '/api/console/proxy'); - expect(args[0]).to.have.property('method', 'post'); - expect(args[0]) - .to.have.property('query') - .eql({ method: 'HEAD', path: '/index/id' }); - expect(args[1]).to.be('http://localhost:9200/index/id?pretty=true'); - }); - - it('sends the returned timeout, agent, and base headers to request', async () => { - const { server } = setup(); - - const timeout = Math.round(Math.random() * 10000); - const agent = new Agent(); - const rejectUnauthorized = !!Math.round(Math.random()); - const headers = { - foo: 'bar', - baz: 'bop', - }; - - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - getConfigForReq: () => ({ - timeout, - agent, - headers, - rejectUnauthorized, - }), - }) - ); - - await server.inject({ - method: 'POST', - url: '/api/console/proxy?method=HEAD&path=/index/id', - }); - - sinon.assert.calledOnce(requestModule.sendRequest); - const opts = requestModule.sendRequest.getCall(0).args[0]; - expect(opts).to.have.property('timeout', timeout); - expect(opts).to.have.property('agent', agent); - expect(opts).to.have.property('rejectUnauthorized', rejectUnauthorized); - expect(opts.headers).to.have.property('foo', 'bar'); - expect(opts.headers).to.have.property('baz', 'bop'); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_route/query_string.js b/src/legacy/core_plugins/console/server/__tests__/proxy_route/query_string.js deleted file mode 100644 index 6b98702131d917..00000000000000 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_route/query_string.js +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import sinon from 'sinon'; -import * as requestModule from '../../request'; -import expect from '@kbn/expect'; -import { Server } from 'hapi'; - -import { createProxyRoute } from '../../'; - -import { createResponseStub } from './stubs'; - -describe('Console Proxy Route', () => { - const sandbox = sinon.createSandbox(); - const teardowns = []; - let request; - - beforeEach(() => { - sandbox.stub(requestModule, 'sendRequest').callsFake(createResponseStub()); - - request = async (method, path) => { - const server = new Server(); - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - }) - ); - - teardowns.push(() => server.stop()); - - const params = []; - if (path != null) params.push(`path=${path}`); - if (method != null) params.push(`method=${method}`); - return await server.inject({ - method: 'POST', - url: `/api/console/proxy${params.length ? `?${params.join('&')}` : ''}`, - }); - }; - }); - - afterEach(async () => { - sandbox.restore(); - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - describe('query string', () => { - describe('path', () => { - describe('contains full url', () => { - it('treats the url as a path', async () => { - await request('GET', 'http://evil.com/test'); - sinon.assert.calledOnce(requestModule.sendRequest); - const args = requestModule.sendRequest.getCall(0).args; - expect(args[0].uri.href).to.be('http://localhost:9200/http://evil.com/test?pretty=true'); - }); - }); - describe('is missing', () => { - it('returns a 400 error', async () => { - const { statusCode } = await request('GET', undefined); - expect(statusCode).to.be(400); - sinon.assert.notCalled(requestModule.sendRequest); - }); - }); - describe('is empty', () => { - it('returns a 400 error', async () => { - const { statusCode } = await request('GET', ''); - expect(statusCode).to.be(400); - sinon.assert.notCalled(requestModule.sendRequest); - }); - }); - describe('starts with a slash', () => { - it('combines well with the base url', async () => { - await request('GET', '/index/id'); - sinon.assert.calledOnce(requestModule.sendRequest); - expect(requestModule.sendRequest.getCall(0).args[0].uri.href).to.be( - 'http://localhost:9200/index/id?pretty=true' - ); - }); - }); - describe(`doesn't start with a slash`, () => { - it('combines well with the base url', async () => { - await request('GET', 'index/id'); - sinon.assert.calledOnce(requestModule.sendRequest); - expect(requestModule.sendRequest.getCall(0).args[0].uri.href).to.be( - 'http://localhost:9200/index/id?pretty=true' - ); - }); - }); - }); - describe('method', () => { - describe('is missing', () => { - it('returns a 400 error', async () => { - const { statusCode } = await request(null, '/'); - expect(statusCode).to.be(400); - sinon.assert.notCalled(requestModule.sendRequest); - }); - }); - describe('is empty', () => { - it('returns a 400 error', async () => { - const { statusCode } = await request('', '/'); - expect(statusCode).to.be(400); - sinon.assert.notCalled(requestModule.sendRequest); - }); - }); - describe('is an invalid http method', () => { - it('returns a 400 error', async () => { - const { statusCode } = await request('foo', '/'); - expect(statusCode).to.be(400); - sinon.assert.notCalled(requestModule.sendRequest); - }); - }); - describe('is mixed case', () => { - it('sends a request with the exact method', async () => { - const { statusCode } = await request('HeAd', '/'); - expect(statusCode).to.be(200); - sinon.assert.calledOnce(requestModule.sendRequest); - expect(requestModule.sendRequest.getCall(0).args[0].method).to.be('HeAd'); - }); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/console/server/proxy_route.ts b/src/legacy/core_plugins/console/server/proxy_route.ts deleted file mode 100644 index f67c97443ba07d..00000000000000 --- a/src/legacy/core_plugins/console/server/proxy_route.ts +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import Joi from 'joi'; -import * as url from 'url'; -import { IncomingMessage } from 'http'; -import Boom from 'boom'; -import { trimLeft, trimRight } from 'lodash'; -import { sendRequest } from './request'; - -function toURL(base: string, path: string) { - const urlResult = new url.URL(`${trimRight(base, '/')}/${trimLeft(path, '/')}`); - // Appending pretty here to have Elasticsearch do the JSON formatting, as doing - // in JS can lead to data loss (7.0 will get munged into 7, thus losing indication of - // measurement precision) - if (!urlResult.searchParams.get('pretty')) { - urlResult.searchParams.append('pretty', 'true'); - } - return urlResult; -} - -function getProxyHeaders(req: any) { - const headers = Object.create(null); - - // Scope this proto-unsafe functionality to where it is being used. - function extendCommaList(obj: Record, property: string, value: any) { - obj[property] = (obj[property] ? obj[property] + ',' : '') + value; - } - - if (req.info.remotePort && req.info.remoteAddress) { - // see https://git.io/vytQ7 - extendCommaList(headers, 'x-forwarded-for', req.info.remoteAddress); - extendCommaList(headers, 'x-forwarded-port', req.info.remotePort); - extendCommaList(headers, 'x-forwarded-proto', req.server.info.protocol); - extendCommaList(headers, 'x-forwarded-host', req.info.host); - } - - const contentType = req.headers['content-type']; - if (contentType) { - headers['content-type'] = contentType; - } - return headers; -} - -export const createProxyRoute = ({ - hosts, - pathFilters = [/.*/], - getConfigForReq = () => ({}), -}: { - hosts: string[]; - pathFilters: RegExp[]; - getConfigForReq: (...args: any[]) => any; -}) => ({ - path: '/api/console/proxy', - method: 'POST', - config: { - tags: ['access:console'], - payload: { - output: 'stream', - parse: false, - }, - validate: { - payload: true, - query: Joi.object() - .keys({ - method: Joi.string() - .valid('HEAD', 'GET', 'POST', 'PUT', 'DELETE') - .insensitive() - .required(), - path: Joi.string().required(), - }) - .unknown(true), - }, - - pre: [ - function filterPath(req: any) { - const { path } = req.query; - - if (pathFilters.some(re => re.test(path))) { - return null; - } - - const err = Boom.forbidden(); - err.output.payload = `Error connecting to '${path}':\n\nUnable to send requests to that path.` as any; - err.output.headers['content-type'] = 'text/plain'; - throw err; - }, - ], - - handler: async (req: any, h: any) => { - const { payload, query } = req; - const { path, method } = query; - - let esIncomingMessage: IncomingMessage; - - for (let idx = 0; idx < hosts.length; ++idx) { - const host = hosts[idx]; - try { - const uri = toURL(host, path); - - // Because this can technically be provided by a settings-defined proxy config, we need to - // preserve these property names to maintain BWC. - const { timeout, agent, headers, rejectUnauthorized } = getConfigForReq( - req, - uri.toString() - ); - - const requestHeaders = { - ...headers, - ...getProxyHeaders(req), - }; - - esIncomingMessage = await sendRequest({ - method, - headers: requestHeaders, - uri, - timeout, - payload, - rejectUnauthorized, - agent, - }); - - break; - } catch (e) { - if (e.code !== 'ECONNREFUSED') { - throw Boom.boomify(e); - } - if (idx === hosts.length - 1) { - throw Boom.badGateway('Could not reach any configured nodes.'); - } - // Otherwise, try the next host... - } - } - - const { - statusCode, - statusMessage, - headers: { warning }, - } = esIncomingMessage!; - - if (method.toUpperCase() !== 'HEAD') { - return h - .response(esIncomingMessage!) - .code(statusCode) - .header('warning', warning!); - } else { - return h - .response(`${statusCode} - ${statusMessage}`) - .code(statusCode) - .type('text/plain') - .header('warning', warning!); - } - }, - }, -}); diff --git a/src/legacy/core_plugins/console_legacy/index.ts b/src/legacy/core_plugins/console_legacy/index.ts new file mode 100644 index 00000000000000..65547e1ee54067 --- /dev/null +++ b/src/legacy/core_plugins/console_legacy/index.ts @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { first } from 'rxjs/operators'; +import { head } from 'lodash'; +import { resolve } from 'path'; +import url from 'url'; + +// TODO: Remove this hack once we can get the ES config we need for Console proxy a better way. +let _legacyEsConfig: any; +export const readLegacyEsConfig = () => { + return _legacyEsConfig; +}; + +// eslint-disable-next-line import/no-default-export +export default function(kibana: any) { + return new kibana.Plugin({ + id: 'console_legacy', + + async init(server: any) { + _legacyEsConfig = await server.newPlatform.__internals.elasticsearch.legacy.config$ + .pipe(first()) + .toPromise(); + }, + + uiExports: { + styleSheetPaths: resolve(__dirname, 'public/styles/index.scss'), + injectDefaultVars: () => ({ + elasticsearchUrl: url.format( + Object.assign(url.parse(head(_legacyEsConfig.hosts)), { auth: false }) + ), + }), + }, + } as any); +} diff --git a/src/legacy/core_plugins/console_legacy/package.json b/src/legacy/core_plugins/console_legacy/package.json new file mode 100644 index 00000000000000..b78807daed9598 --- /dev/null +++ b/src/legacy/core_plugins/console_legacy/package.json @@ -0,0 +1,4 @@ +{ + "name": "console_legacy", + "version": "kibana" +} diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss b/src/legacy/core_plugins/console_legacy/public/styles/_app.scss similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss rename to src/legacy/core_plugins/console_legacy/public/styles/_app.scss diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss b/src/legacy/core_plugins/console_legacy/public/styles/components/_help.scss similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss rename to src/legacy/core_plugins/console_legacy/public/styles/components/_help.scss diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss b/src/legacy/core_plugins/console_legacy/public/styles/components/_history.scss similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss rename to src/legacy/core_plugins/console_legacy/public/styles/components/_history.scss diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss b/src/legacy/core_plugins/console_legacy/public/styles/components/_index.scss similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss rename to src/legacy/core_plugins/console_legacy/public/styles/components/_index.scss diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss b/src/legacy/core_plugins/console_legacy/public/styles/index.scss similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss rename to src/legacy/core_plugins/console_legacy/public/styles/index.scss diff --git a/src/legacy/core_plugins/console/common/text_object.ts b/src/plugins/console/common/text_object.ts similarity index 100% rename from src/legacy/core_plugins/console/common/text_object.ts rename to src/plugins/console/common/text_object.ts diff --git a/src/plugins/console/common/types/index.ts b/src/plugins/console/common/types/index.ts new file mode 100644 index 00000000000000..65e02b859d1ac4 --- /dev/null +++ b/src/plugins/console/common/types/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './models'; +export * from './plugin_config'; diff --git a/src/legacy/core_plugins/console/common/types.ts b/src/plugins/console/common/types/models.ts similarity index 97% rename from src/legacy/core_plugins/console/common/types.ts rename to src/plugins/console/common/types/models.ts index 33d6907ff60b88..de118761aea542 100644 --- a/src/legacy/core_plugins/console/common/types.ts +++ b/src/plugins/console/common/types/models.ts @@ -17,7 +17,7 @@ * under the License. */ -import { TextObject } from './text_object'; +import { TextObject } from '../text_object'; export interface IdObject { id: string; diff --git a/src/plugins/console/common/types/plugin_config.ts b/src/plugins/console/common/types/plugin_config.ts new file mode 100644 index 00000000000000..965c301d8b0861 --- /dev/null +++ b/src/plugins/console/common/types/plugin_config.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface PluginServerConfig { + elasticsearchUrl: string; +} diff --git a/src/legacy/core_plugins/console/public/kibana.json b/src/plugins/console/kibana.json similarity index 73% rename from src/legacy/core_plugins/console/public/kibana.json rename to src/plugins/console/kibana.json index c58a5a90fb9f28..18f7eb06e98ed9 100644 --- a/src/legacy/core_plugins/console/public/kibana.json +++ b/src/plugins/console/kibana.json @@ -3,6 +3,6 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["home"], + "requiredPlugins": ["dev_tools", "home"], "optionalPlugins": ["usageCollection"] } diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx b/src/plugins/console/public/application/components/console_menu.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx rename to src/plugins/console/public/application/components/console_menu.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/editor_content_spinner.tsx b/src/plugins/console/public/application/components/editor_content_spinner.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/editor_content_spinner.tsx rename to src/plugins/console/public/application/components/editor_content_spinner.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx b/src/plugins/console/public/application/components/editor_example.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx rename to src/plugins/console/public/application/components/editor_example.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx b/src/plugins/console/public/application/components/help_panel.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx rename to src/plugins/console/public/application/components/help_panel.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/index.ts b/src/plugins/console/public/application/components/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/index.ts rename to src/plugins/console/public/application/components/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx b/src/plugins/console/public/application/components/settings_modal.tsx similarity index 98% rename from src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx rename to src/plugins/console/public/application/components/settings_modal.tsx index 05afdc9b79e0f4..3cd20bf1bc3432 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx +++ b/src/plugins/console/public/application/components/settings_modal.tsx @@ -248,7 +248,10 @@ export function DevToolsSettingsModal(props: Props) { } > { + const { stateSetter, ...rest } = opts; + return rest; + })} idToSelectedMap={checkboxIdToSelectedMap} onChange={(e: any) => { onAutocompleteChange(e as AutocompleteOptions); diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/something_went_wrong_callout.tsx b/src/plugins/console/public/application/components/something_went_wrong_callout.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/something_went_wrong_callout.tsx rename to src/plugins/console/public/application/components/something_went_wrong_callout.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx b/src/plugins/console/public/application/components/top_nav_menu.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx rename to src/plugins/console/public/application/components/top_nav_menu.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx b/src/plugins/console/public/application/components/welcome_panel.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx rename to src/plugins/console/public/application/components/welcome_panel.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt b/src/plugins/console/public/application/constants/help_example.txt similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt rename to src/plugins/console/public/application/constants/help_example.txt diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx b/src/plugins/console/public/application/containers/console_history/console_history.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx rename to src/plugins/console/public/application/containers/console_history/console_history.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx b/src/plugins/console/public/application/containers/console_history/history_viewer.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx rename to src/plugins/console/public/application/containers/console_history/history_viewer.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts b/src/plugins/console/public/application/containers/console_history/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts rename to src/plugins/console/public/application/containers/console_history/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx b/src/plugins/console/public/application/containers/editor/editor.tsx similarity index 96% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx rename to src/plugins/console/public/application/containers/editor/editor.tsx index b42d791e5acd8e..5c7fe293651fbd 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/editor.tsx @@ -21,7 +21,7 @@ import React, { useCallback } from 'react'; import { debounce } from 'lodash'; import { EditorContentSpinner } from '../../components'; -import { Panel, PanelsContainer } from '../../../../../../../../plugins/kibana_react/public'; +import { Panel, PanelsContainer } from '../../../../../kibana_react/public'; import { Editor as EditorUI, EditorOutput } from './legacy/console_editor'; import { StorageKeys } from '../../../services'; import { useEditorReadContext, useServicesContext } from '../../contexts'; diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts b/src/plugins/console/public/application/containers/editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts rename to src/plugins/console/public/application/containers/editor/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts b/src/plugins/console/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.test.tsx similarity index 99% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.test.tsx index d4079fcea33f87..306cdd396f4f82 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx +++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.test.tsx @@ -25,7 +25,7 @@ import { I18nProvider } from '@kbn/i18n/react'; import { act } from 'react-dom/test-utils'; import * as sinon from 'sinon'; -import { notificationServiceMock } from '../../../../../../../../../../../src/core/public/mocks'; +import { notificationServiceMock } from '../../../../../../../../core/public/mocks'; import { nextTick } from 'test_utils/enzyme_helpers'; import { diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/editor_output.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts b/src/plugins/console/public/application/containers/editor/legacy/console_editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts b/src/plugins/console/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts rename to src/plugins/console/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts b/src/plugins/console/public/application/containers/editor/legacy/console_menu_actions.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts rename to src/plugins/console/public/application/containers/editor/legacy/console_menu_actions.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts b/src/plugins/console/public/application/containers/editor/legacy/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts rename to src/plugins/console/public/application/containers/editor/legacy/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts b/src/plugins/console/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts similarity index 93% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts rename to src/plugins/console/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts index 1adc56d47927be..2d992aadbf15ad 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts +++ b/src/plugins/console/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts @@ -16,7 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { ResizeChecker } from '../../../../../../../../../plugins/kibana_utils/public'; + +import { ResizeChecker } from '../../../../../../kibana_utils/public'; export function subscribeResizeChecker(el: HTMLElement, ...editors: any[]) { const checker = new ResizeChecker(el); diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx b/src/plugins/console/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx rename to src/plugins/console/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts b/src/plugins/console/public/application/containers/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts rename to src/plugins/console/public/application/containers/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts b/src/plugins/console/public/application/containers/main/get_top_nav.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts rename to src/plugins/console/public/application/containers/main/get_top_nav.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts b/src/plugins/console/public/application/containers/main/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts rename to src/plugins/console/public/application/containers/main/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx b/src/plugins/console/public/application/containers/main/main.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx rename to src/plugins/console/public/application/containers/main/main.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx b/src/plugins/console/public/application/containers/settings.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx rename to src/plugins/console/public/application/containers/settings.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts b/src/plugins/console/public/application/contexts/create_use_context.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts rename to src/plugins/console/public/application/contexts/create_use_context.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx b/src/plugins/console/public/application/contexts/editor_context/editor_context.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx rename to src/plugins/console/public/application/contexts/editor_context/editor_context.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts b/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts rename to src/plugins/console/public/application/contexts/editor_context/editor_registry.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts b/src/plugins/console/public/application/contexts/editor_context/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts rename to src/plugins/console/public/application/contexts/editor_context/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts b/src/plugins/console/public/application/contexts/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts rename to src/plugins/console/public/application/contexts/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx b/src/plugins/console/public/application/contexts/request_context.tsx similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx rename to src/plugins/console/public/application/contexts/request_context.tsx diff --git a/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx b/src/plugins/console/public/application/contexts/services_context.tsx similarity index 96% rename from src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx rename to src/plugins/console/public/application/contexts/services_context.tsx index d7f036e1aecb61..4393cab4adbc56 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx +++ b/src/plugins/console/public/application/contexts/services_context.tsx @@ -20,7 +20,7 @@ import React, { createContext, useContext } from 'react'; import { NotificationsSetup } from 'kibana/public'; import { History, Storage, Settings } from '../../services'; -import { ObjectStorageClient } from '../../../../common/types'; +import { ObjectStorageClient } from '../../../common/types'; import { MetricsTracker } from '../../types'; export interface ContextValue { diff --git a/src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts b/src/plugins/console/public/application/factories/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts rename to src/plugins/console/public/application/factories/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts b/src/plugins/console/public/application/factories/token_iterator.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts rename to src/plugins/console/public/application/factories/token_iterator.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts b/src/plugins/console/public/application/hooks/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts rename to src/plugins/console/public/application/hooks/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/data_migration.ts b/src/plugins/console/public/application/hooks/use_data_init/data_migration.ts similarity index 95% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/data_migration.ts rename to src/plugins/console/public/application/hooks/use_data_init/data_migration.ts index 08acd78ba2b8a0..67d39c37a2f45f 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/data_migration.ts +++ b/src/plugins/console/public/application/hooks/use_data_init/data_migration.ts @@ -18,7 +18,7 @@ */ import { History } from '../../../services'; -import { ObjectStorageClient } from '../../../../../common/types'; +import { ObjectStorageClient } from '../../../../common/types'; export interface Dependencies { history: History; diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/index.ts b/src/plugins/console/public/application/hooks/use_data_init/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/index.ts rename to src/plugins/console/public/application/hooks/use_data_init/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/use_data_init.ts b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_data_init/use_data_init.ts rename to src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts rename to src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts rename to src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts rename to src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_save_current_text_object.ts b/src/plugins/console/public/application/hooks/use_save_current_text_object.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_save_current_text_object.ts rename to src/plugins/console/public/application/hooks/use_save_current_text_object.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts rename to src/plugins/console/public/application/hooks/use_send_current_request_to_es/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts rename to src/plugins/console/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/track.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/track.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/track.ts rename to src/plugins/console/public/application/hooks/use_send_current_request_to_es/track.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts rename to src/plugins/console/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts b/src/plugins/console/public/application/hooks/use_set_input_editor.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts rename to src/plugins/console/public/application/hooks/use_set_input_editor.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/index.tsx b/src/plugins/console/public/application/index.tsx similarity index 81% rename from src/legacy/core_plugins/console/public/np_ready/application/index.tsx rename to src/plugins/console/public/application/index.tsx index efd0f2ba860240..1fef52da6f31bf 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/index.tsx +++ b/src/plugins/console/public/application/index.tsx @@ -18,27 +18,38 @@ */ import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; import { NotificationsSetup } from 'src/core/public'; import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts'; import { Main } from './containers'; import { createStorage, createHistory, createSettings, Settings } from '../services'; import * as localStorageObjectClient from '../lib/local_storage_object_client'; import { createUsageTracker } from '../services/tracker'; +import { UsageCollectionSetup } from '../../../usage_collection/public'; let settingsRef: Settings; export function legacyBackDoorToSettings() { return settingsRef; } -export function boot(deps: { +export interface BootDependencies { docLinkVersion: string; I18nContext: any; notifications: NotificationsSetup; elasticsearchUrl: string; -}) { - const { I18nContext, notifications, docLinkVersion, elasticsearchUrl } = deps; + usageCollection?: UsageCollectionSetup; + element: HTMLElement; +} - const trackUiMetric = createUsageTracker(); +export function renderApp({ + I18nContext, + notifications, + docLinkVersion, + elasticsearchUrl, + usageCollection, + element, +}: BootDependencies) { + const trackUiMetric = createUsageTracker(usageCollection); trackUiMetric.load('opened_app'); const storage = createStorage({ @@ -50,7 +61,7 @@ export function boot(deps: { const objectStorageClient = localStorageObjectClient.create(storage); settingsRef = settings; - return ( + render( - + , + element ); + + return () => unmountComponentAtNode(element); } diff --git a/src/legacy/core_plugins/console/public/np_ready/application/logo.svg b/src/plugins/console/public/application/logo.svg similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/logo.svg rename to src/plugins/console/public/application/logo.svg diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/index.ts b/src/plugins/console/public/application/models/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/index.ts rename to src/plugins/console/public/application/models/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/input_tokenization.test.js b/src/plugins/console/public/application/models/legacy_core_editor/__tests__/input_tokenization.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/input_tokenization.test.js rename to src/plugins/console/public/application/models/legacy_core_editor/__tests__/input_tokenization.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js b/src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js rename to src/plugins/console/public/application/models/legacy_core_editor/__tests__/output_tokenization.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts b/src/plugins/console/public/application/models/legacy_core_editor/create.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts rename to src/plugins/console/public/application/models/legacy_core_editor/create.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts b/src/plugins/console/public/application/models/legacy_core_editor/create_readonly.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts rename to src/plugins/console/public/application/models/legacy_core_editor/create_readonly.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts b/src/plugins/console/public/application/models/legacy_core_editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts rename to src/plugins/console/public/application/models/legacy_core_editor/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts b/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts rename to src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts b/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts rename to src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/elasticsearch_sql_highlight_rules.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/elasticsearch_sql_highlight_rules.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/elasticsearch_sql_highlight_rules.ts rename to src/plugins/console/public/application/models/legacy_core_editor/mode/elasticsearch_sql_highlight_rules.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/input.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/input.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/output.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/output.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/script.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/script.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/script_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/script_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/x_json_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js rename to src/plugins/console/public/application/models/legacy_core_editor/mode/x_json_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts b/src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts rename to src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js b/src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js rename to src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt b/src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt rename to src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js b/src/plugins/console/public/application/models/sense_editor/__tests__/integration.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js rename to src/plugins/console/public/application/models/sense_editor/__tests__/integration.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js b/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js rename to src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts b/src/plugins/console/public/application/models/sense_editor/create.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts rename to src/plugins/console/public/application/models/sense_editor/create.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts b/src/plugins/console/public/application/models/sense_editor/curl.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts rename to src/plugins/console/public/application/models/sense_editor/curl.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts b/src/plugins/console/public/application/models/sense_editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts rename to src/plugins/console/public/application/models/sense_editor/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts rename to src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts rename to src/plugins/console/public/application/models/sense_editor/sense_editor.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts b/src/plugins/console/public/application/stores/editor.ts similarity index 96% rename from src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts rename to src/plugins/console/public/application/stores/editor.ts index 844eacd9b91a8c..73c29e7ff85754 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts +++ b/src/plugins/console/public/application/stores/editor.ts @@ -21,7 +21,7 @@ import { Reducer } from 'react'; import { produce } from 'immer'; import { identity } from 'fp-ts/lib/function'; import { DevToolsSettings } from '../../services'; -import { TextObject } from '../../../../common/text_object'; +import { TextObject } from '../../../common/text_object'; export interface Store { ready: boolean; diff --git a/src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts b/src/plugins/console/public/application/stores/request.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts rename to src/plugins/console/public/application/stores/request.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/index.ts b/src/plugins/console/public/index.ts similarity index 85% rename from src/legacy/core_plugins/console/public/np_ready/index.ts rename to src/plugins/console/public/index.ts index 045420f401e3ba..2af9d1d16af020 100644 --- a/src/legacy/core_plugins/console/public/np_ready/index.ts +++ b/src/plugins/console/public/index.ts @@ -17,12 +17,10 @@ * under the License. */ -import { PluginInitializerContext } from 'kibana/public'; - import { ConsoleUIPlugin } from './plugin'; export { ConsoleUIPlugin as Plugin }; -export function plugin(ctx: PluginInitializerContext) { - return new ConsoleUIPlugin(ctx); +export function plugin() { + return new ConsoleUIPlugin(); } diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts b/src/plugins/console/public/lib/ace_token_provider/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts rename to src/plugins/console/public/lib/ace_token_provider/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts b/src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts rename to src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts b/src/plugins/console/public/lib/ace_token_provider/token_provider.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts rename to src/plugins/console/public/lib/ace_token_provider/token_provider.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js b/src/plugins/console/public/lib/autocomplete/__tests__/url_autocomplete.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js rename to src/plugins/console/public/lib/autocomplete/__tests__/url_autocomplete.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js b/src/plugins/console/public/lib/autocomplete/__tests__/url_params.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js rename to src/plugins/console/public/lib/autocomplete/__tests__/url_params.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts b/src/plugins/console/public/lib/autocomplete/autocomplete.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts rename to src/plugins/console/public/lib/autocomplete/autocomplete.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js b/src/plugins/console/public/lib/autocomplete/body_completer.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js rename to src/plugins/console/public/lib/autocomplete/body_completer.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js b/src/plugins/console/public/lib/autocomplete/components/accept_endpoint_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js rename to src/plugins/console/public/lib/autocomplete/components/accept_endpoint_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js b/src/plugins/console/public/lib/autocomplete/components/conditional_proxy.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js rename to src/plugins/console/public/lib/autocomplete/components/conditional_proxy.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js b/src/plugins/console/public/lib/autocomplete/components/constant_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js rename to src/plugins/console/public/lib/autocomplete/components/constant_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/field_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/field_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/full_request_component.ts b/src/plugins/console/public/lib/autocomplete/components/full_request_component.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/full_request_component.ts rename to src/plugins/console/public/lib/autocomplete/components/full_request_component.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js b/src/plugins/console/public/lib/autocomplete/components/global_only_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js rename to src/plugins/console/public/lib/autocomplete/components/global_only_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/id_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/id_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js b/src/plugins/console/public/lib/autocomplete/components/index.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js rename to src/plugins/console/public/lib/autocomplete/components/index.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/index_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/index_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js b/src/plugins/console/public/lib/autocomplete/components/list_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js rename to src/plugins/console/public/lib/autocomplete/components/list_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js b/src/plugins/console/public/lib/autocomplete/components/object_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js rename to src/plugins/console/public/lib/autocomplete/components/object_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js b/src/plugins/console/public/lib/autocomplete/components/shared_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js rename to src/plugins/console/public/lib/autocomplete/components/shared_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js b/src/plugins/console/public/lib/autocomplete/components/simple_param_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js rename to src/plugins/console/public/lib/autocomplete/components/simple_param_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/template_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/template_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/type_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/type_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js b/src/plugins/console/public/lib/autocomplete/components/url_pattern_matcher.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js rename to src/plugins/console/public/lib/autocomplete/components/url_pattern_matcher.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js b/src/plugins/console/public/lib/autocomplete/components/username_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js rename to src/plugins/console/public/lib/autocomplete/components/username_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js b/src/plugins/console/public/lib/autocomplete/engine.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js rename to src/plugins/console/public/lib/autocomplete/engine.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/get_endpoint_from_position.ts b/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/get_endpoint_from_position.ts rename to src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js b/src/plugins/console/public/lib/autocomplete/url_params.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js rename to src/plugins/console/public/lib/autocomplete/url_params.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js b/src/plugins/console/public/lib/curl_parsing/__tests__/curl_parsing.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js rename to src/plugins/console/public/lib/curl_parsing/__tests__/curl_parsing.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt b/src/plugins/console/public/lib/curl_parsing/__tests__/curl_parsing.txt similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt rename to src/plugins/console/public/lib/curl_parsing/__tests__/curl_parsing.txt diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js b/src/plugins/console/public/lib/curl_parsing/curl.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js rename to src/plugins/console/public/lib/curl_parsing/curl.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js b/src/plugins/console/public/lib/es/__tests__/content_type.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js rename to src/plugins/console/public/lib/es/__tests__/content_type.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/es/es.js b/src/plugins/console/public/lib/es/es.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/es/es.js rename to src/plugins/console/public/lib/es/es.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js b/src/plugins/console/public/lib/kb/__tests__/kb.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js rename to src/plugins/console/public/lib/kb/__tests__/kb.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js b/src/plugins/console/public/lib/kb/api.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js rename to src/plugins/console/public/lib/kb/api.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js b/src/plugins/console/public/lib/kb/index.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js rename to src/plugins/console/public/lib/kb/index.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js b/src/plugins/console/public/lib/kb/kb.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js rename to src/plugins/console/public/lib/kb/kb.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/create.ts b/src/plugins/console/public/lib/local_storage_object_client/create.ts similarity index 88% rename from src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/create.ts rename to src/plugins/console/public/lib/local_storage_object_client/create.ts index 36948b9acb9626..503387f7b4a419 100644 --- a/src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/create.ts +++ b/src/plugins/console/public/lib/local_storage_object_client/create.ts @@ -18,8 +18,8 @@ */ import { Storage } from '../../services'; -import { ObjectStorageClient } from '../../../../common/types'; -import { TextObject, textObjectTypeName } from '../../../../common/text_object'; +import { ObjectStorageClient } from '../../../common/types'; +import { TextObject, textObjectTypeName } from '../../../common/text_object'; import { LocalObjectStorage } from './local_storage_object_client'; export const create = (storage: Storage): ObjectStorageClient => { diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/index.ts b/src/plugins/console/public/lib/local_storage_object_client/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/index.ts rename to src/plugins/console/public/lib/local_storage_object_client/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/local_storage_object_client.ts b/src/plugins/console/public/lib/local_storage_object_client/local_storage_object_client.ts similarity index 96% rename from src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/local_storage_object_client.ts rename to src/plugins/console/public/lib/local_storage_object_client/local_storage_object_client.ts index 41c88d23b2533d..8eac345898f9a4 100644 --- a/src/legacy/core_plugins/console/public/np_ready/lib/local_storage_object_client/local_storage_object_client.ts +++ b/src/plugins/console/public/lib/local_storage_object_client/local_storage_object_client.ts @@ -18,7 +18,7 @@ */ import uuid from 'uuid'; -import { ObjectStorage, IdObject } from '../../../../common/types'; +import { ObjectStorage, IdObject } from '../../../common/types'; import { Storage } from '../../services'; export class LocalObjectStorage implements ObjectStorage { diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js b/src/plugins/console/public/lib/mappings/__tests__/mapping.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js rename to src/plugins/console/public/lib/mappings/__tests__/mapping.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js b/src/plugins/console/public/lib/mappings/mappings.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js rename to src/plugins/console/public/lib/mappings/mappings.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts b/src/plugins/console/public/lib/row_parser.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts rename to src/plugins/console/public/lib/row_parser.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts b/src/plugins/console/public/lib/token_iterator/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts rename to src/plugins/console/public/lib/token_iterator/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts b/src/plugins/console/public/lib/token_iterator/token_iterator.test.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts rename to src/plugins/console/public/lib/token_iterator/token_iterator.test.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts b/src/plugins/console/public/lib/token_iterator/token_iterator.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts rename to src/plugins/console/public/lib/token_iterator/token_iterator.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js b/src/plugins/console/public/lib/utils/__tests__/utils.test.js similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js rename to src/plugins/console/public/lib/utils/__tests__/utils.test.js diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt b/src/plugins/console/public/lib/utils/__tests__/utils_string_collapsing.txt similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt rename to src/plugins/console/public/lib/utils/__tests__/utils_string_collapsing.txt diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt b/src/plugins/console/public/lib/utils/__tests__/utils_string_expanding.txt similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt rename to src/plugins/console/public/lib/utils/__tests__/utils_string_expanding.txt diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts b/src/plugins/console/public/lib/utils/utils.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts rename to src/plugins/console/public/lib/utils/utils.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/plugin.ts b/src/plugins/console/public/plugin.ts similarity index 58% rename from src/legacy/core_plugins/console/public/np_ready/plugin.ts rename to src/plugins/console/public/plugin.ts index 22351ae95ba872..71a5e150a9f00c 100644 --- a/src/legacy/core_plugins/console/public/np_ready/plugin.ts +++ b/src/plugins/console/public/plugin.ts @@ -17,23 +17,21 @@ * under the License. */ -import { render, unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; -import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from 'src/core/public'; -import { XPluginSet } from '../legacy'; +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -export class ConsoleUIPlugin implements Plugin { - // @ts-ignore - constructor(private readonly ctx: PluginInitializerContext) {} +import { FeatureCatalogueCategory } from '../../home/public'; - async setup({ notifications }: CoreSetup, pluginSet: XPluginSet) { - const { - __LEGACY: { I18nContext, elasticsearchUrl, category }, - dev_tools, - home, - } = pluginSet; +import { AppSetupUIPluginDependencies } from './types'; +export class ConsoleUIPlugin implements Plugin { + constructor() {} + + async setup( + { notifications, getStartServices }: CoreSetup, + { dev_tools, home, usageCollection }: AppSetupUIPluginDependencies + ) { home.featureCatalogue.register({ id: 'console', title: i18n.translate('console.devToolsTitle', { @@ -45,7 +43,7 @@ export class ConsoleUIPlugin implements Plugin { icon: 'consoleApp', path: '/app/kibana#/dev_tools/console', showOnHomePage: true, - category, + category: FeatureCatalogueCategory.ADMIN, }); dev_tools.register({ @@ -55,20 +53,21 @@ export class ConsoleUIPlugin implements Plugin { defaultMessage: 'Console', }), enableRouting: false, - async mount({ core: { docLinks } }, { element }) { - const { boot } = await import('./application'); - render( - boot({ - docLinkVersion: docLinks.DOC_LINK_VERSION, - I18nContext, - notifications, - elasticsearchUrl, - }), - element - ); - return () => { - unmountComponentAtNode(element); - }; + mount: async ({ core: { docLinks, i18n: i18nDep } }, { element }) => { + const { renderApp } = await import('./application'); + const [{ injectedMetadata }] = await getStartServices(); + const elasticsearchUrl = injectedMetadata.getInjectedVar( + 'elasticsearchUrl', + 'http://localhost:9200' + ) as string; + return renderApp({ + docLinkVersion: docLinks.DOC_LINK_VERSION, + I18nContext: i18nDep.Context, + notifications, + elasticsearchUrl, + usageCollection, + element, + }); }, }); } diff --git a/src/legacy/core_plugins/console/public/np_ready/services/history.ts b/src/plugins/console/public/services/history.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/services/history.ts rename to src/plugins/console/public/services/history.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/services/index.ts b/src/plugins/console/public/services/index.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/services/index.ts rename to src/plugins/console/public/services/index.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/services/settings.ts b/src/plugins/console/public/services/settings.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/services/settings.ts rename to src/plugins/console/public/services/settings.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/services/storage.ts b/src/plugins/console/public/services/storage.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/services/storage.ts rename to src/plugins/console/public/services/storage.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/services/tracker.ts b/src/plugins/console/public/services/tracker.ts similarity index 62% rename from src/legacy/core_plugins/console/public/np_ready/services/tracker.ts rename to src/plugins/console/public/services/tracker.ts index 13d5f875b3c6fb..f5abcd145d0f7b 100644 --- a/src/legacy/core_plugins/console/public/np_ready/services/tracker.ts +++ b/src/plugins/console/public/services/tracker.ts @@ -17,15 +17,22 @@ * under the License. */ -import { METRIC_TYPE } from '@kbn/analytics'; +import { METRIC_TYPE, UiStatsMetricType } from '@kbn/analytics'; import { MetricsTracker } from '../types'; -import { createUiStatsReporter } from '../../../../ui_metric/public'; +import { UsageCollectionSetup } from '../../../usage_collection/public'; const APP_TRACKER_NAME = 'console'; -export const createUsageTracker = (): MetricsTracker => { - const track = createUiStatsReporter(APP_TRACKER_NAME); + +export const createUsageTracker = (usageCollection?: UsageCollectionSetup): MetricsTracker => { + const track = (type: UiStatsMetricType, name: string) => + usageCollection?.reportUiStats(APP_TRACKER_NAME, type, name); + return { - count: (eventName: string) => track(METRIC_TYPE.COUNT, eventName), - load: (eventName: string) => track(METRIC_TYPE.LOADED, eventName), + count: (eventName: string) => { + track(METRIC_TYPE.COUNT, eventName); + }, + load: (eventName: string) => { + track(METRIC_TYPE.LOADED, eventName); + }, }; }; diff --git a/src/legacy/core_plugins/console/public/np_ready/types/common.ts b/src/plugins/console/public/types/common.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/types/common.ts rename to src/plugins/console/public/types/common.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts b/src/plugins/console/public/types/core_editor.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts rename to src/plugins/console/public/types/core_editor.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/types/index.ts b/src/plugins/console/public/types/index.ts similarity index 95% rename from src/legacy/core_plugins/console/public/np_ready/types/index.ts rename to src/plugins/console/public/types/index.ts index 78c6b6c8f55cc3..555a0ea82c523c 100644 --- a/src/legacy/core_plugins/console/public/np_ready/types/index.ts +++ b/src/plugins/console/public/types/index.ts @@ -17,6 +17,7 @@ * under the License. */ +export * from './plugin_dependencies'; export * from './core_editor'; export * from './token'; export * from './tokens_provider'; diff --git a/src/plugins/console/public/types/plugin_dependencies.ts b/src/plugins/console/public/types/plugin_dependencies.ts new file mode 100644 index 00000000000000..6bc4ff25ee442d --- /dev/null +++ b/src/plugins/console/public/types/plugin_dependencies.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { HomePublicPluginSetup } from '../../../home/public'; +import { DevToolsSetup } from '../../../dev_tools/public'; +import { UsageCollectionSetup } from '../../../usage_collection/public'; + +export interface AppSetupUIPluginDependencies { + home: HomePublicPluginSetup; + dev_tools: DevToolsSetup; + usageCollection?: UsageCollectionSetup; +} diff --git a/src/legacy/core_plugins/console/public/np_ready/types/token.ts b/src/plugins/console/public/types/token.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/types/token.ts rename to src/plugins/console/public/types/token.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts b/src/plugins/console/public/types/tokens_provider.ts similarity index 100% rename from src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts rename to src/plugins/console/public/types/tokens_provider.ts diff --git a/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js b/src/plugins/console/server/__tests__/elasticsearch_proxy_config.js similarity index 98% rename from src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js rename to src/plugins/console/server/__tests__/elasticsearch_proxy_config.js index ec7d256975b27e..df8b49b0a089ee 100644 --- a/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js +++ b/src/plugins/console/server/__tests__/elasticsearch_proxy_config.js @@ -19,7 +19,7 @@ import expect from '@kbn/expect'; import moment from 'moment'; -import { getElasticsearchProxyConfig } from '../elasticsearch_proxy_config'; +import { getElasticsearchProxyConfig } from '../lib/elasticsearch_proxy_config'; import https from 'https'; import http from 'http'; diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_config.js b/src/plugins/console/server/__tests__/proxy_config.js similarity index 99% rename from src/legacy/core_plugins/console/server/__tests__/proxy_config.js rename to src/plugins/console/server/__tests__/proxy_config.js index 2a221aa2611677..b0b85e6bb7d061 100644 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_config.js +++ b/src/plugins/console/server/__tests__/proxy_config.js @@ -24,7 +24,7 @@ import sinon from 'sinon'; import https, { Agent as HttpsAgent } from 'https'; import { parse as parseUrl } from 'url'; -import { ProxyConfig } from '../proxy_config'; +import { ProxyConfig } from '../lib/proxy_config'; const matchGoogle = { protocol: 'https', diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js b/src/plugins/console/server/__tests__/proxy_config_collection.js similarity index 98% rename from src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js rename to src/plugins/console/server/__tests__/proxy_config_collection.js index 1791ca9865d250..e1bc099ac1e856 100644 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js +++ b/src/plugins/console/server/__tests__/proxy_config_collection.js @@ -24,7 +24,7 @@ import sinon from 'sinon'; import fs from 'fs'; import { Agent as HttpsAgent } from 'https'; -import { ProxyConfigCollection } from '../proxy_config_collection'; +import { ProxyConfigCollection } from '../lib/proxy_config_collection'; describe('ProxyConfigCollection', function() { beforeEach(function() { diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_route/body.js b/src/plugins/console/server/__tests__/proxy_route/body.test.ts similarity index 63% rename from src/legacy/core_plugins/console/server/__tests__/proxy_route/body.js rename to src/plugins/console/server/__tests__/proxy_route/body.test.ts index 923567769a6b8b..252009a8977f39 100644 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_route/body.js +++ b/src/plugins/console/server/__tests__/proxy_route/body.test.ts @@ -16,79 +16,83 @@ * specific language governing permissions and limitations * under the License. */ +import { getProxyRouteHandlerDeps } from './mocks'; -import sinon from 'sinon'; import expect from '@kbn/expect'; -import { Server } from 'hapi'; +import { Readable } from 'stream'; + +import { kibanaResponseFactory } from '../../../../../core/server'; +import { createHandler } from '../../routes/api/console/proxy/create_handler'; +import * as requestModule from '../../lib/proxy_request'; import { createResponseStub } from './stubs'; -import { createProxyRoute } from '../../'; -import * as requestModule from '../../request'; describe('Console Proxy Route', () => { - const sandbox = sinon.createSandbox(); - const teardowns = []; - let request; + let request: any; beforeEach(() => { - request = async (method, path, response) => { - sandbox.stub(requestModule, 'sendRequest').callsFake(createResponseStub(response)); - const server = new Server(); - server.route( - createProxyRoute({ - hosts: ['http://localhost:9200'], - }) - ); + request = (method: string, path: string, response: string) => { + (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub(response)); + const handler = createHandler(getProxyRouteHandlerDeps({})); - teardowns.push(() => server.stop()); - - const params = []; - if (path != null) params.push(`path=${path}`); - if (method != null) params.push(`method=${method}`); - return await server.inject({ - method: 'POST', - url: `/api/console/proxy${params.length ? `?${params.join('&')}` : ''}`, - }); + return handler( + {} as any, + { + headers: {}, + query: { method, path }, + } as any, + kibanaResponseFactory + ); }; }); + const readStream = (s: Readable) => + new Promise(resolve => { + let v = ''; + s.on('data', data => { + v += data; + }); + s.on('end', () => resolve(v)); + }); + afterEach(async () => { - sandbox.restore(); - await Promise.all(teardowns.splice(0).map(fn => fn())); + jest.resetAllMocks(); }); describe('response body', () => { describe('GET request', () => { it('returns the exact body', async () => { const { payload } = await request('GET', '/', 'foobar'); - expect(payload).to.be('foobar'); + expect(await readStream(payload)).to.be('foobar'); }); }); describe('POST request', () => { it('returns the exact body', async () => { const { payload } = await request('POST', '/', 'foobar'); - expect(payload).to.be('foobar'); + expect(await readStream(payload)).to.be('foobar'); }); }); describe('PUT request', () => { it('returns the exact body', async () => { const { payload } = await request('PUT', '/', 'foobar'); - expect(payload).to.be('foobar'); + expect(await readStream(payload)).to.be('foobar'); }); }); describe('DELETE request', () => { it('returns the exact body', async () => { const { payload } = await request('DELETE', '/', 'foobar'); - expect(payload).to.be('foobar'); + expect(await readStream(payload)).to.be('foobar'); }); }); describe('HEAD request', () => { it('returns the status code and text', async () => { const { payload } = await request('HEAD', '/'); + expect(typeof payload).to.be('string'); expect(payload).to.be('200 - OK'); }); describe('mixed casing', () => { it('returns the status code and text', async () => { const { payload } = await request('HeAd', '/'); + expect(typeof payload).to.be('string'); expect(payload).to.be('200 - OK'); }); }); diff --git a/src/plugins/console/server/__tests__/proxy_route/headers.test.ts b/src/plugins/console/server/__tests__/proxy_route/headers.test.ts new file mode 100644 index 00000000000000..8a779715ac8235 --- /dev/null +++ b/src/plugins/console/server/__tests__/proxy_route/headers.test.ts @@ -0,0 +1,89 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +jest.mock('../../../../../core/server/http/router/request', () => ({ + ensureRawRequest: jest.fn(), +})); + +import { kibanaResponseFactory } from '../../../../../core/server'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ensureRawRequest } from '../../../../../core/server/http/router/request'; + +import { getProxyRouteHandlerDeps } from './mocks'; + +import expect from '@kbn/expect'; +import * as requestModule from '../../lib/proxy_request'; + +import { createHandler } from '../../routes/api/console/proxy/create_handler'; + +import { createResponseStub } from './stubs'; + +describe('Console Proxy Route', () => { + let handler: ReturnType; + + beforeEach(() => { + (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('')); + handler = createHandler(getProxyRouteHandlerDeps({})); + }); + + afterEach(async () => { + jest.resetAllMocks(); + }); + + describe('headers', () => { + it('forwards the remote header info', async () => { + (ensureRawRequest as jest.Mock).mockReturnValue({ + // This mocks the shape of the hapi request object, will probably change + info: { + remoteAddress: '0.0.0.0', + remotePort: '1234', + host: 'test', + }, + server: { + info: { + protocol: 'http', + }, + }, + }); + + await handler( + {} as any, + { + headers: {}, + query: { + method: 'POST', + path: '/api/console/proxy?method=GET&path=/', + }, + } as any, + kibanaResponseFactory + ); + + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + const [[{ headers }]] = (requestModule.proxyRequest as jest.Mock).mock.calls; + expect(headers).to.have.property('x-forwarded-for'); + expect(headers['x-forwarded-for']).to.be('0.0.0.0'); + expect(headers).to.have.property('x-forwarded-port'); + expect(headers['x-forwarded-port']).to.be('1234'); + expect(headers).to.have.property('x-forwarded-proto'); + expect(headers['x-forwarded-proto']).to.be('http'); + expect(headers).to.have.property('x-forwarded-host'); + expect(headers['x-forwarded-host']).to.be('test'); + }); + }); +}); diff --git a/src/plugins/console/server/__tests__/proxy_route/mocks.ts b/src/plugins/console/server/__tests__/proxy_route/mocks.ts new file mode 100644 index 00000000000000..74bd43fe521461 --- /dev/null +++ b/src/plugins/console/server/__tests__/proxy_route/mocks.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +jest.mock('../../lib/proxy_request', () => ({ + proxyRequest: jest.fn(), +})); + +import { duration } from 'moment'; +import { ProxyConfigCollection } from '../../lib'; +import { CreateHandlerDependencies } from '../../routes/api/console/proxy/create_handler'; +import { coreMock } from '../../../../../core/server/mocks'; + +export const getProxyRouteHandlerDeps = ({ + proxyConfigCollection = new ProxyConfigCollection([]), + pathFilters = [/.*/], + readLegacyESConfig = () => ({ + requestTimeout: duration(30000), + customHeaders: {}, + requestHeadersWhitelist: [], + hosts: ['http://localhost:9200'], + }), + log = coreMock.createPluginInitializerContext().logger.get(), +}: Partial): CreateHandlerDependencies => ({ + proxyConfigCollection, + pathFilters, + readLegacyESConfig, + log, +}); diff --git a/src/plugins/console/server/__tests__/proxy_route/params.test.ts b/src/plugins/console/server/__tests__/proxy_route/params.test.ts new file mode 100644 index 00000000000000..1ab9c3ae789cc1 --- /dev/null +++ b/src/plugins/console/server/__tests__/proxy_route/params.test.ts @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { kibanaResponseFactory } from '../../../../../core/server'; +import { getProxyRouteHandlerDeps } from './mocks'; +import { createResponseStub } from './stubs'; +import * as requestModule from '../../lib/proxy_request'; +import expect from '@kbn/expect'; + +import { createHandler } from '../../routes/api/console/proxy/create_handler'; + +describe('Console Proxy Route', () => { + let handler: ReturnType; + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('params', () => { + describe('pathFilters', () => { + describe('no matches', () => { + it('rejects with 403', async () => { + handler = createHandler( + getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//, /^\/bar\//] }) + ); + + const { status } = await handler( + {} as any, + { query: { method: 'POST', path: '/baz/id' } } as any, + kibanaResponseFactory + ); + + expect(status).to.be(403); + }); + }); + describe('one match', () => { + it('allows the request', async () => { + handler = createHandler( + getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//, /^\/bar\//] }) + ); + + (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo')); + + const { status } = await handler( + {} as any, + { headers: {}, query: { method: 'POST', path: '/foo/id' } } as any, + kibanaResponseFactory + ); + + expect(status).to.be(200); + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + }); + }); + describe('all match', () => { + it('allows the request', async () => { + handler = createHandler(getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//] })); + + (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo')); + + const { status } = await handler( + {} as any, + { headers: {}, query: { method: 'GET', path: '/foo/id' } } as any, + kibanaResponseFactory + ); + + expect(status).to.be(200); + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + }); + }); + }); + }); +}); diff --git a/src/plugins/console/server/__tests__/proxy_route/query_string.test.ts b/src/plugins/console/server/__tests__/proxy_route/query_string.test.ts new file mode 100644 index 00000000000000..028022db1096d7 --- /dev/null +++ b/src/plugins/console/server/__tests__/proxy_route/query_string.test.ts @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { kibanaResponseFactory } from '../../../../../core/server'; +import { getProxyRouteHandlerDeps } from './mocks'; +import { createResponseStub } from './stubs'; +import * as requestModule from '../../lib/proxy_request'; + +import expect from '@kbn/expect'; + +import { createHandler } from '../../routes/api/console/proxy/create_handler'; + +describe('Console Proxy Route', () => { + let request: any; + beforeEach(() => { + (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo')); + + request = async (method: string, path: string) => { + const handler = createHandler(getProxyRouteHandlerDeps({})); + + return handler( + {} as any, + { headers: {}, query: { method, path } } as any, + kibanaResponseFactory + ); + }; + }); + + afterEach(async () => { + jest.resetAllMocks(); + }); + + describe('query string', () => { + describe('path', () => { + describe('contains full url', () => { + it('treats the url as a path', async () => { + await request('GET', 'http://evil.com/test'); + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + const [[args]] = (requestModule.proxyRequest as jest.Mock).mock.calls; + expect(args.uri.href).to.be('http://localhost:9200/http://evil.com/test?pretty=true'); + }); + }); + describe('starts with a slash', () => { + it('combines well with the base url', async () => { + await request('GET', '/index/id'); + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + const [[args]] = (requestModule.proxyRequest as jest.Mock).mock.calls; + expect(args.uri.href).to.be('http://localhost:9200/index/id?pretty=true'); + }); + }); + describe(`doesn't start with a slash`, () => { + it('combines well with the base url', async () => { + await request('GET', 'index/id'); + expect((requestModule.proxyRequest as jest.Mock).mock.calls.length).to.be(1); + const [[args]] = (requestModule.proxyRequest as jest.Mock).mock.calls; + expect(args.uri.href).to.be('http://localhost:9200/index/id?pretty=true'); + }); + }); + }); + }); +}); diff --git a/src/plugins/console/server/__tests__/proxy_route/route_validation.test.ts b/src/plugins/console/server/__tests__/proxy_route/route_validation.test.ts new file mode 100644 index 00000000000000..403ef9737ae421 --- /dev/null +++ b/src/plugins/console/server/__tests__/proxy_route/route_validation.test.ts @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { routeValidationConfig } from '../../routes/api/console/proxy/validation_config'; + +const { query } = routeValidationConfig; + +describe('Proxy route validation', () => { + describe('query', () => { + describe('allows', () => { + it('known http verb method and path value', () => { + expect(query.validate({ method: 'GET', path: 'test' })); + }); + it('mixed case http verbs', () => { + expect(query.validate({ method: 'hEaD', path: 'test' })); + }); + }); + describe('throws for', () => { + it('empty query method value', () => { + expect(() => { + query.validate({ method: '', path: 'test' }); + }).toThrow('Method must be one of'); + }); + it('unknown method value', () => { + expect(() => { + query.validate({ method: 'abc', path: 'test' }); + }).toThrow('Method must be one of'); + }); + it('empty path value', () => { + expect(() => { + query.validate({ method: 'GET', path: '' }); + }).toThrow('Expected non-empty string'); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_route/stubs.js b/src/plugins/console/server/__tests__/proxy_route/stubs.ts similarity index 65% rename from src/legacy/core_plugins/console/server/__tests__/proxy_route/stubs.js rename to src/plugins/console/server/__tests__/proxy_route/stubs.ts index 18ad277c0bf6b0..12ad9cbe26e9c4 100644 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_route/stubs.js +++ b/src/plugins/console/server/__tests__/proxy_route/stubs.ts @@ -16,27 +16,25 @@ * specific language governing permissions and limitations * under the License. */ - +import { IncomingMessage } from 'http'; import { Readable } from 'stream'; -export function createResponseStub(response) { - return async () => { - const resp = new Readable({ - read() { - if (response) { - this.push(response); - } - this.push(null); - }, - }); - - resp.statusCode = 200; - resp.statusMessage = 'OK'; - resp.headers = { - 'content-type': 'text/plain', - 'content-length': String(response ? response.length : 0), - }; +export function createResponseStub(response: any) { + const resp: any = new Readable({ + read() { + if (response) { + this.push(response); + } + this.push(null); + }, + }); - return resp; + resp.statusCode = 200; + resp.statusMessage = 'OK'; + resp.headers = { + 'content-type': 'text/plain', + 'content-length': String(response ? response.length : 0), }; + + return resp as IncomingMessage; } diff --git a/src/legacy/core_plugins/console/server/__tests__/set_headers.js b/src/plugins/console/server/__tests__/set_headers.js similarity index 97% rename from src/legacy/core_plugins/console/server/__tests__/set_headers.js rename to src/plugins/console/server/__tests__/set_headers.js index 3cab23a05884f1..1f349cbbb571ee 100644 --- a/src/legacy/core_plugins/console/server/__tests__/set_headers.js +++ b/src/plugins/console/server/__tests__/set_headers.js @@ -18,7 +18,7 @@ */ import expect from '@kbn/expect'; -import { setHeaders } from '../set_headers'; +import { setHeaders } from '../lib'; describe('#set_headers', function() { it('throws if not given an object as the first argument', function() { diff --git a/src/legacy/core_plugins/console/server/__tests__/wildcard_matcher.js b/src/plugins/console/server/__tests__/wildcard_matcher.js similarity index 98% rename from src/legacy/core_plugins/console/server/__tests__/wildcard_matcher.js rename to src/plugins/console/server/__tests__/wildcard_matcher.js index ef0588973ab297..ccf68f3c16ca36 100644 --- a/src/legacy/core_plugins/console/server/__tests__/wildcard_matcher.js +++ b/src/plugins/console/server/__tests__/wildcard_matcher.js @@ -18,7 +18,7 @@ */ /* eslint-env mocha */ -import { WildcardMatcher } from '../wildcard_matcher'; +import { WildcardMatcher } from '../lib/wildcard_matcher'; function should(candidate, ...constructorArgs) { if (!new WildcardMatcher(...constructorArgs).match(candidate)) { diff --git a/src/plugins/console/server/config.ts b/src/plugins/console/server/config.ts new file mode 100644 index 00000000000000..ebd4b37bb41b2b --- /dev/null +++ b/src/plugins/console/server/config.ts @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export type ConfigType = TypeOf; + +export const config = schema.object( + { + enabled: schema.boolean({ defaultValue: true }), + proxyFilter: schema.arrayOf(schema.string(), { defaultValue: ['.*'] }), + ssl: schema.object({ verify: schema.boolean({ defaultValue: false }) }, {}), + + // This does not actually work, track this issue: https://github.com/elastic/kibana/issues/55576 + proxyConfig: schema.arrayOf( + schema.object({ + match: schema.object({ + protocol: schema.string({ defaultValue: '*' }), + host: schema.string({ defaultValue: '*' }), + port: schema.string({ defaultValue: '*' }), + path: schema.string({ defaultValue: '*' }), + }), + + timeout: schema.number(), + ssl: schema.object( + { + verify: schema.boolean(), + ca: schema.arrayOf(schema.string()), + cert: schema.string(), + key: schema.string(), + }, + { defaultValue: undefined } + ), + }), + { defaultValue: [] } + ), + }, + { defaultValue: undefined } +); diff --git a/src/plugins/console/server/index.ts b/src/plugins/console/server/index.ts new file mode 100644 index 00000000000000..b603deee12e23d --- /dev/null +++ b/src/plugins/console/server/index.ts @@ -0,0 +1,31 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { PluginConfigDescriptor, PluginInitializerContext } from 'kibana/server'; + +import { ConfigType, config as configSchema } from './config'; +import { ConsoleServerPlugin } from './plugin'; + +export { ConsoleSetup } from './types'; + +export const plugin = (ctx: PluginInitializerContext) => new ConsoleServerPlugin(ctx); + +export const config: PluginConfigDescriptor = { + deprecations: ({ unused }) => [unused('ssl')], + schema: configSchema, +}; diff --git a/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.ts b/src/plugins/console/server/lib/elasticsearch_proxy_config.ts similarity index 94% rename from src/legacy/core_plugins/console/server/elasticsearch_proxy_config.ts rename to src/plugins/console/server/lib/elasticsearch_proxy_config.ts index 5f44a524e9cc8d..901d726ac51d82 100644 --- a/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.ts +++ b/src/plugins/console/server/lib/elasticsearch_proxy_config.ts @@ -21,6 +21,7 @@ import _ from 'lodash'; import http from 'http'; import https from 'https'; import url from 'url'; +import { Duration } from 'moment'; const createAgent = (legacyConfig: any) => { const target = url.parse(_.head(legacyConfig.hosts)); @@ -58,7 +59,7 @@ const createAgent = (legacyConfig: any) => { return new https.Agent(agentOptions); }; -export const getElasticsearchProxyConfig = (legacyConfig: any) => { +export const getElasticsearchProxyConfig = (legacyConfig: { requestTimeout: Duration }) => { return { timeout: legacyConfig.requestTimeout.asMilliseconds(), agent: createAgent(legacyConfig), diff --git a/src/legacy/core_plugins/console/server/index.js b/src/plugins/console/server/lib/index.ts similarity index 80% rename from src/legacy/core_plugins/console/server/index.js rename to src/plugins/console/server/lib/index.ts index 15a8a5baf79dc0..98004768f880b7 100644 --- a/src/legacy/core_plugins/console/server/index.js +++ b/src/plugins/console/server/lib/index.ts @@ -17,6 +17,9 @@ * under the License. */ +export { ProxyConfig } from './proxy_config'; export { ProxyConfigCollection } from './proxy_config_collection'; +export { proxyRequest } from './proxy_request'; export { getElasticsearchProxyConfig } from './elasticsearch_proxy_config'; -export { createProxyRoute } from './proxy_route'; +export { setHeaders } from './set_headers'; +export { addProcessorDefinition, addExtensionSpecFilePath } from './spec_definitions'; diff --git a/src/legacy/core_plugins/console/server/proxy_config.js b/src/plugins/console/server/lib/proxy_config.ts similarity index 80% rename from src/legacy/core_plugins/console/server/proxy_config.js rename to src/plugins/console/server/lib/proxy_config.ts index b8c1b11f9a0d35..5adb9c58f784e3 100644 --- a/src/legacy/core_plugins/console/server/proxy_config.js +++ b/src/plugins/console/server/lib/proxy_config.ts @@ -19,12 +19,27 @@ import { values } from 'lodash'; import { format as formatUrl } from 'url'; -import { Agent as HttpsAgent } from 'https'; +import { Agent as HttpsAgent, AgentOptions } from 'https'; import { WildcardMatcher } from './wildcard_matcher'; export class ProxyConfig { - constructor(config) { + // @ts-ignore + private id: string; + private matchers: { + protocol: WildcardMatcher; + host: WildcardMatcher; + port: WildcardMatcher; + path: WildcardMatcher; + }; + + private readonly timeout: number; + + private readonly sslAgent?: HttpsAgent; + + private verifySsl: any; + + constructor(config: { match: any; timeout: number }) { config = { ...config, }; @@ -57,11 +72,11 @@ export class ProxyConfig { this.sslAgent = this._makeSslAgent(config); } - _makeSslAgent(config) { + _makeSslAgent(config: any) { const ssl = config.ssl || {}; this.verifySsl = ssl.verify; - const sslAgentOpts = { + const sslAgentOpts: AgentOptions = { ca: ssl.ca, cert: ssl.cert, key: ssl.key, @@ -73,7 +88,12 @@ export class ProxyConfig { } } - getForParsedUri({ protocol, hostname, port, pathname }) { + getForParsedUri({ + protocol, + hostname, + port, + pathname, + }: Record<'protocol' | 'hostname' | 'port' | 'pathname', string>) { let match = this.matchers.protocol.match(protocol.slice(0, -1)); match = match && this.matchers.host.match(hostname); match = match && this.matchers.port.match(port); diff --git a/src/legacy/core_plugins/console/server/proxy_config_collection.js b/src/plugins/console/server/lib/proxy_config_collection.ts similarity index 83% rename from src/legacy/core_plugins/console/server/proxy_config_collection.js rename to src/plugins/console/server/lib/proxy_config_collection.ts index 79bc057aaaf7f3..5d0b02fed5b18e 100644 --- a/src/legacy/core_plugins/console/server/proxy_config_collection.js +++ b/src/plugins/console/server/lib/proxy_config_collection.ts @@ -18,18 +18,24 @@ */ import { defaultsDeep } from 'lodash'; +import { parse as parseUrl } from 'url'; import { ProxyConfig } from './proxy_config'; -import { parse as parseUrl } from 'url'; export class ProxyConfigCollection { - constructor(configs = []) { + private configs: ProxyConfig[]; + + constructor(configs: Array<{ match: any; timeout: number }> = []) { this.configs = configs.map(settings => new ProxyConfig(settings)); } - configForUri(uri) { + hasConfig() { + return Boolean(this.configs.length); + } + + configForUri(uri: string): object { const parsedUri = parseUrl(uri); - const settings = this.configs.map(config => config.getForParsedUri(parsedUri)); + const settings = this.configs.map(config => config.getForParsedUri(parsedUri as any)); return defaultsDeep({}, ...settings); } } diff --git a/src/legacy/core_plugins/console/server/request.test.ts b/src/plugins/console/server/lib/proxy_request.test.ts similarity index 96% rename from src/legacy/core_plugins/console/server/request.test.ts rename to src/plugins/console/server/lib/proxy_request.test.ts index 2cbde5b3b39b85..0285daef7d725e 100644 --- a/src/legacy/core_plugins/console/server/request.test.ts +++ b/src/plugins/console/server/lib/proxy_request.test.ts @@ -18,7 +18,7 @@ */ import http, { ClientRequest } from 'http'; import * as sinon from 'sinon'; -import { sendRequest } from './request'; +import { proxyRequest } from './proxy_request'; import { URL } from 'url'; import { fail } from 'assert'; @@ -46,7 +46,7 @@ describe(`Console's send request`, () => { it('correctly implements timeout and abort mechanism', async () => { try { - await sendRequest({ + await proxyRequest({ agent: null as any, headers: {}, method: 'get', diff --git a/src/legacy/core_plugins/console/server/request.ts b/src/plugins/console/server/lib/proxy_request.ts similarity index 99% rename from src/legacy/core_plugins/console/server/request.ts rename to src/plugins/console/server/lib/proxy_request.ts index 0f6b78b484adf7..ed02b23d77f6a4 100644 --- a/src/legacy/core_plugins/console/server/request.ts +++ b/src/plugins/console/server/lib/proxy_request.ts @@ -37,7 +37,7 @@ interface Args { // We use a modified version of Hapi's Wreck because Hapi, Axios, and Superagent don't support GET requests // with bodies, but ES APIs do. Similarly with DELETE requests with bodies. Another library, `request` // diverged too much from current behaviour. -export const sendRequest = ({ +export const proxyRequest = ({ method, headers, agent, diff --git a/src/legacy/core_plugins/console/server/set_headers.js b/src/plugins/console/server/lib/set_headers.ts similarity index 94% rename from src/legacy/core_plugins/console/server/set_headers.js rename to src/plugins/console/server/lib/set_headers.ts index 5ea4c214dc42ed..ee0be40312a4d5 100644 --- a/src/legacy/core_plugins/console/server/set_headers.js +++ b/src/plugins/console/server/lib/set_headers.ts @@ -19,7 +19,7 @@ import { isPlainObject } from 'lodash'; -export function setHeaders(originalHeaders, newHeaders) { +export function setHeaders(originalHeaders: object, newHeaders: object) { if (!isPlainObject(originalHeaders)) { throw new Error( `Expected originalHeaders to be an object, but ${typeof originalHeaders} given` diff --git a/src/legacy/core_plugins/console/server/api_server/api.js b/src/plugins/console/server/lib/spec_definitions/api.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/api.js rename to src/plugins/console/server/lib/spec_definitions/api.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0.js b/src/plugins/console/server/lib/spec_definitions/es_6_0.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/aggregations.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/aggregations.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/aggregations.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/aggregations.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/aliases.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/aliases.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/aliases.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/aliases.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/document.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/document.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/document.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/document.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/filter.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/filter.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/globals.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/globals.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/globals.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/globals.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/ingest.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/ingest.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/ingest.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/ingest.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/mappings.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/mappings.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/mappings.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/mappings.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/query/dsl.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/query/dsl.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/query/index.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/query/index.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/query/index.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/query/index.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/query/templates.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/query/templates.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/query/templates.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/query/templates.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/reindex.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/reindex.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/reindex.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/reindex.js diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/search.js b/src/plugins/console/server/lib/spec_definitions/es_6_0/search.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/es_6_0/search.js rename to src/plugins/console/server/lib/spec_definitions/es_6_0/search.js diff --git a/src/plugins/console/server/lib/spec_definitions/index.d.ts b/src/plugins/console/server/lib/spec_definitions/index.d.ts new file mode 100644 index 00000000000000..0a79d3fb386f1c --- /dev/null +++ b/src/plugins/console/server/lib/spec_definitions/index.d.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export declare function addProcessorDefinition(...args: any[]): any; + +export declare function resolveApi(senseVersion: string, apis: string[]): object; + +export declare function addExtensionSpecFilePath(...args: any[]): any; diff --git a/src/plugins/console/server/lib/spec_definitions/index.js b/src/plugins/console/server/lib/spec_definitions/index.js new file mode 100644 index 00000000000000..3fe1913d5a193a --- /dev/null +++ b/src/plugins/console/server/lib/spec_definitions/index.js @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { addProcessorDefinition } from './es_6_0/ingest'; + +export { addExtensionSpecFilePath } from './spec'; + +export { resolveApi } from './server'; diff --git a/src/legacy/core_plugins/console/server/api_server/server.js b/src/plugins/console/server/lib/spec_definitions/server.js similarity index 91% rename from src/legacy/core_plugins/console/server/api_server/server.js rename to src/plugins/console/server/lib/spec_definitions/server.js index 48ed73cb3611dd..dd700bf0195075 100644 --- a/src/legacy/core_plugins/console/server/api_server/server.js +++ b/src/plugins/console/server/lib/spec_definitions/server.js @@ -21,7 +21,7 @@ import _ from 'lodash'; const KNOWN_APIS = ['es_6_0']; -export function resolveApi(senseVersion, apis, h) { +export function resolveApi(senseVersion, apis) { const result = {}; _.each(apis, function(name) { { @@ -33,5 +33,5 @@ export function resolveApi(senseVersion, apis, h) { } }); - return h.response(result).type('application/json'); + return result; } diff --git a/src/legacy/core_plugins/console/server/api_server/server.test.js b/src/plugins/console/server/lib/spec_definitions/server.test.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/server.test.js rename to src/plugins/console/server/lib/spec_definitions/server.test.js diff --git a/src/legacy/core_plugins/console/server/api_server/spec/.eslintrc b/src/plugins/console/server/lib/spec_definitions/spec/.eslintrc similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/.eslintrc rename to src/plugins/console/server/lib/spec_definitions/spec/.eslintrc diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/_common.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/_common.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/_common.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/_common.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/bulk.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/bulk.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/bulk.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/bulk.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.aliases.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.aliases.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.aliases.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.aliases.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.allocation.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.allocation.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.allocation.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.allocation.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.count.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.count.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.count.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.count.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.fielddata.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.fielddata.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.fielddata.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.fielddata.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.health.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.health.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.health.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.health.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.help.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.help.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.help.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.help.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.indices.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.indices.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.indices.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.indices.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.master.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.master.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.master.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.master.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.nodeattrs.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodeattrs.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.nodeattrs.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodeattrs.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.nodes.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodes.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.nodes.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodes.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.pending_tasks.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.pending_tasks.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.pending_tasks.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.pending_tasks.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.plugins.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.plugins.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.plugins.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.plugins.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.recovery.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.recovery.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.recovery.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.recovery.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.repositories.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.repositories.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.repositories.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.repositories.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.segments.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.segments.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.segments.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.segments.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.shards.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.shards.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.shards.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.shards.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.snapshots.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.snapshots.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.snapshots.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.snapshots.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.tasks.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.tasks.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.tasks.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.tasks.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.templates.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.templates.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.templates.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.templates.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cat.thread_pool.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.thread_pool.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cat.thread_pool.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cat.thread_pool.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/clear_scroll.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/clear_scroll.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/clear_scroll.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/clear_scroll.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.allocation_explain.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.allocation_explain.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.allocation_explain.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.allocation_explain.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.get_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.get_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.get_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.get_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.health.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.health.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.health.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.health.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.pending_tasks.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.pending_tasks.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.pending_tasks.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.pending_tasks.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.put_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.put_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.put_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.put_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.remote_info.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.remote_info.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.remote_info.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.remote_info.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.reroute.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.reroute.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.reroute.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.reroute.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.state.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.state.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.state.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.state.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.stats.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.stats.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/cluster.stats.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.stats.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/count.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/count.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/count.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/count.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/create.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/create.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/create.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/create.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/delete.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/delete.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/delete.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/delete.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/delete_by_query.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/delete_by_query.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/delete_by_query_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query_rethrottle.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/delete_by_query_rethrottle.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query_rethrottle.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/delete_script.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_script.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/delete_script.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/delete_script.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/exists.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/exists.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/exists.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/exists.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/exists_source.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/exists_source.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/exists_source.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/exists_source.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/explain.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/explain.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/explain.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/explain.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/field_caps.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/field_caps.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/field_caps.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/field_caps.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/get.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/get.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/get.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/get.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/get_script.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/get_script.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/get_script.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/get_script_context.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_context.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/get_script_context.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_context.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/get_script_languages.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_languages.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/get_script_languages.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_languages.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/get_source.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/get_source.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/get_source.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/get_source.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/index.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/index.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/index.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/index.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.analyze.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.analyze.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.analyze.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.analyze.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.clear_cache.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clear_cache.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.clear_cache.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clear_cache.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.clone.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clone.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.clone.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clone.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.close.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.close.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.close.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.close.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.create.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.create.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.create.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.create.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete_alias.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_alias.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete_alias.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_alias.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.delete_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_alias.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_alias.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_alias.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_alias.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_type.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_type.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.exists_type.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_type.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.flush.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.flush.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.flush_synced.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush_synced.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.flush_synced.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush_synced.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.forcemerge.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.forcemerge.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.forcemerge.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.forcemerge.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_alias.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_alias.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_alias.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_alias.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_field_mapping.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_field_mapping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_field_mapping.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_field_mapping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_mapping.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_mapping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_mapping.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_mapping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_upgrade.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_upgrade.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.get_upgrade.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_upgrade.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.open.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.open.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.open.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.open.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_alias.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_alias.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_alias.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_alias.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_mapping.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_mapping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_mapping.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_mapping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.put_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.recovery.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.recovery.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.recovery.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.recovery.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.refresh.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.refresh.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.refresh.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.refresh.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.rollover.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.rollover.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.rollover.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.rollover.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.segments.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.segments.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.segments.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.segments.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.shard_stores.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shard_stores.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.shard_stores.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shard_stores.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.shrink.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shrink.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.shrink.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shrink.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.split.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.split.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.split.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.split.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.stats.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.stats.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.stats.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.stats.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.update_aliases.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.update_aliases.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.update_aliases.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.update_aliases.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.upgrade.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.upgrade.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.upgrade.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.upgrade.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/indices.validate_query.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.validate_query.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/indices.validate_query.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/indices.validate_query.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/info.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/info.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/info.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/info.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.delete_pipeline.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.delete_pipeline.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.delete_pipeline.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.delete_pipeline.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.get_pipeline.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.get_pipeline.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.get_pipeline.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.get_pipeline.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.processor_grok.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.processor_grok.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.processor_grok.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.processor_grok.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.put_pipeline.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.put_pipeline.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.put_pipeline.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.put_pipeline.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.simulate.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.simulate.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ingest.simulate.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.simulate.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/mget.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/mget.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/mget.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/mget.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/msearch.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/msearch.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/msearch.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/msearch.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/msearch_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/msearch_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/msearch_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/msearch_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/mtermvectors.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/mtermvectors.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/mtermvectors.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/mtermvectors.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.hot_threads.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.hot_threads.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.hot_threads.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.hot_threads.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.info.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.info.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.info.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.info.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.reload_secure_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.reload_secure_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.reload_secure_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.reload_secure_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.stats.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.stats.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.stats.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.stats.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.usage.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.usage.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/nodes.usage.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.usage.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/ping.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/ping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/ping.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/ping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/put_script.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/put_script.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/put_script.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/put_script.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/rank_eval.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/rank_eval.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/rank_eval.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/rank_eval.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/reindex.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/reindex.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/reindex.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/reindex.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/reindex_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/reindex_rethrottle.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/reindex_rethrottle.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/reindex_rethrottle.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/render_search_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/render_search_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/render_search_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/render_search_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/scripts_painless_execute.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/scripts_painless_execute.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/scripts_painless_execute.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/scripts_painless_execute.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/scroll.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/scroll.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/scroll.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/scroll.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/search.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/search.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/search.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/search.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/search_shards.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/search_shards.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/search_shards.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/search_shards.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/search_template.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/search_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/search_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/search_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.cleanup_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.cleanup_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.cleanup_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.cleanup_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.create.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.create.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.create_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.create_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.delete.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.delete.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.delete_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.delete_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.get.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.get.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.get_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.get_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.restore.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.restore.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.restore.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.restore.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.status.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.status.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.status.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.status.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.verify_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.verify_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/snapshot.verify_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.verify_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.cancel.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.cancel.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.cancel.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.cancel.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.get.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.get.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.get.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.get.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.list.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.list.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/tasks.list.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.list.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/termvectors.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/termvectors.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/termvectors.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/termvectors.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/update.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/update.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/update.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/update.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/update_by_query.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/update_by_query.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/generated/update_by_query_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query_rethrottle.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/generated/update_by_query_rethrottle.json rename to src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query_rethrottle.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/index.js b/src/plugins/console/server/lib/spec_definitions/spec/index.js similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/index.js rename to src/plugins/console/server/lib/spec_definitions/spec/index.js diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/clear_scroll.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/clear_scroll.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/clear_scroll.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/clear_scroll.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.health.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.health.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.health.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.health.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.put_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.put_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.put_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.put_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.reroute.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.reroute.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/cluster.reroute.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.reroute.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/count.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/count.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/count.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/count.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.analyze.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.analyze.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.analyze.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.analyze.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.clone.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.clone.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.clone.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.clone.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.create.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.create.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.create.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.create.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.delete_template.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.delete_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.delete_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.delete_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.exists_template.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.exists_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.exists_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.exists_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_field_mapping.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_field_mapping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_field_mapping.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_field_mapping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_mapping.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_mapping.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_mapping.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_mapping.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_template.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.get_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_alias.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_alias.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_alias.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_alias.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_settings.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_settings.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_settings.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_template.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_template.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.put_template.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_template.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.rollover.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.rollover.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.rollover.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.rollover.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.update_aliases.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.update_aliases.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.update_aliases.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.update_aliases.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.validate_query.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.validate_query.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/indices.validate_query.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.validate_query.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.create.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.create.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.create_repository.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create_repository.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.create_repository.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create_repository.json diff --git a/src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.restore.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.restore.json similarity index 100% rename from src/legacy/core_plugins/console/server/api_server/spec/overrides/snapshot.restore.json rename to src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.restore.json diff --git a/src/legacy/core_plugins/console/server/wildcard_matcher.js b/src/plugins/console/server/lib/wildcard_matcher.ts similarity index 81% rename from src/legacy/core_plugins/console/server/wildcard_matcher.js rename to src/plugins/console/server/lib/wildcard_matcher.ts index b99fba9295e51e..128ad19172c752 100644 --- a/src/legacy/core_plugins/console/server/wildcard_matcher.js +++ b/src/plugins/console/server/lib/wildcard_matcher.ts @@ -17,12 +17,14 @@ * under the License. */ -import { Minimatch } from 'minimatch'; +import { Minimatch, IMinimatch } from 'minimatch'; export class WildcardMatcher { - constructor(wildcardPattern, emptyVal) { - this.emptyVal = emptyVal; - this.pattern = String(wildcardPattern || '*'); + pattern: string; + matcher: IMinimatch; + + constructor(private readonly wildcardPattern: string, private readonly emptyVal?: string) { + this.pattern = String(this.wildcardPattern || '*'); this.matcher = new Minimatch(this.pattern, { noglobstar: true, dot: true, @@ -32,7 +34,7 @@ export class WildcardMatcher { }); } - match(candidate) { + match(candidate: string) { const empty = !candidate || candidate === this.emptyVal; if (empty && this.pattern === '*') { return true; diff --git a/src/plugins/console/server/plugin.ts b/src/plugins/console/server/plugin.ts new file mode 100644 index 00000000000000..c8ef84aee3b615 --- /dev/null +++ b/src/plugins/console/server/plugin.ts @@ -0,0 +1,81 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { first } from 'rxjs/operators'; +import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server'; + +import { readLegacyEsConfig } from '../../../legacy/core_plugins/console_legacy'; + +import { ProxyConfigCollection, addExtensionSpecFilePath, addProcessorDefinition } from './lib'; +import { ConfigType } from './config'; +import { registerProxyRoute } from './routes/api/console/proxy'; +import { registerSpecDefinitionsRoute } from './routes/api/console/spec_definitions'; +import { ESConfigForProxy, ConsoleSetup } from './types'; + +export class ConsoleServerPlugin implements Plugin { + log: Logger; + + constructor(private readonly ctx: PluginInitializerContext) { + this.log = this.ctx.logger.get(); + } + + async setup({ http, capabilities, getStartServices }: CoreSetup) { + capabilities.registerProvider(() => ({ + dev_tools: { + show: true, + save: true, + }, + })); + + const config = await this.ctx.config + .create() + .pipe(first()) + .toPromise(); + + const { elasticsearch } = await this.ctx.config.legacy.globalConfig$.pipe(first()).toPromise(); + + const proxyPathFilters = config.proxyFilter.map((str: string) => new RegExp(str)); + + const router = http.createRouter(); + + registerProxyRoute({ + log: this.log, + proxyConfigCollection: new ProxyConfigCollection(config.proxyConfig), + readLegacyESConfig: (): ESConfigForProxy => { + const legacyConfig = readLegacyEsConfig(); + return { + ...elasticsearch, + hosts: legacyConfig.hosts, + requestHeadersWhitelist: legacyConfig.requestHeadersWhitelist, + customHeaders: legacyConfig.customHeaders, + }; + }, + pathFilters: proxyPathFilters, + router, + }); + + registerSpecDefinitionsRoute({ router }); + + return { + addExtensionSpecFilePath, + addProcessorDefinition, + }; + } + + start() {} +} diff --git a/src/plugins/console/server/routes/api/console/proxy/create_handler.ts b/src/plugins/console/server/routes/api/console/proxy/create_handler.ts new file mode 100644 index 00000000000000..50a9fcf03c2093 --- /dev/null +++ b/src/plugins/console/server/routes/api/console/proxy/create_handler.ts @@ -0,0 +1,217 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Agent, IncomingMessage } from 'http'; +import * as url from 'url'; +import { pick, trimLeft, trimRight } from 'lodash'; + +import { KibanaRequest, Logger, RequestHandler } from 'kibana/server'; + +import { ESConfigForProxy } from '../../../../types'; +import { + getElasticsearchProxyConfig, + ProxyConfigCollection, + proxyRequest, + setHeaders, +} from '../../../../lib'; + +import { Body, Query } from './validation_config'; + +// TODO: find a better way to get information from the request like remoteAddress and remotePort +// for forwarding. +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ensureRawRequest } from '../../../../../../../core/server/http/router'; + +export interface CreateHandlerDependencies { + log: Logger; + readLegacyESConfig: () => ESConfigForProxy; + pathFilters: RegExp[]; + proxyConfigCollection: ProxyConfigCollection; +} + +function toURL(base: string, path: string) { + const urlResult = new url.URL(`${trimRight(base, '/')}/${trimLeft(path, '/')}`); + // Appending pretty here to have Elasticsearch do the JSON formatting, as doing + // in JS can lead to data loss (7.0 will get munged into 7, thus losing indication of + // measurement precision) + if (!urlResult.searchParams.get('pretty')) { + urlResult.searchParams.append('pretty', 'true'); + } + return urlResult; +} + +function filterHeaders(originalHeaders: object, headersToKeep: string[]): object { + const normalizeHeader = function(header: any) { + if (!header) { + return ''; + } + header = header.toString(); + return header.trim().toLowerCase(); + }; + + // Normalize list of headers we want to allow in upstream request + const headersToKeepNormalized = headersToKeep.map(normalizeHeader); + + return pick(originalHeaders, headersToKeepNormalized); +} + +function getRequestConfig( + headers: object, + esConfig: ESConfigForProxy, + proxyConfigCollection: ProxyConfigCollection, + uri: string +): { agent: Agent; timeout: number; headers: object; rejectUnauthorized?: boolean } { + const filteredHeaders = filterHeaders(headers, esConfig.requestHeadersWhitelist); + const newHeaders = setHeaders(filteredHeaders, esConfig.customHeaders); + + if (proxyConfigCollection.hasConfig()) { + return { + ...proxyConfigCollection.configForUri(uri), + headers: newHeaders, + } as any; + } + + return { + ...getElasticsearchProxyConfig(esConfig), + headers: newHeaders, + }; +} + +function getProxyHeaders(req: KibanaRequest) { + const headers = Object.create(null); + + // Scope this proto-unsafe functionality to where it is being used. + function extendCommaList(obj: Record, property: string, value: any) { + obj[property] = (obj[property] ? obj[property] + ',' : '') + value; + } + + const _req = ensureRawRequest(req); + + if (_req?.info?.remotePort && _req?.info?.remoteAddress) { + // see https://git.io/vytQ7 + extendCommaList(headers, 'x-forwarded-for', _req.info.remoteAddress); + extendCommaList(headers, 'x-forwarded-port', _req.info.remotePort); + extendCommaList(headers, 'x-forwarded-proto', _req.server.info.protocol); + extendCommaList(headers, 'x-forwarded-host', _req.info.host); + } + + const contentType = req.headers['content-type']; + if (contentType) { + headers['content-type'] = contentType; + } + return headers; +} + +export const createHandler = ({ + log, + readLegacyESConfig, + pathFilters, + proxyConfigCollection, +}: CreateHandlerDependencies): RequestHandler => async ( + ctx, + request, + response +) => { + const { body, query } = request; + const { path, method } = query; + + if (!pathFilters.some(re => re.test(path))) { + return response.forbidden({ + body: `Error connecting to '${path}':\n\nUnable to send requests to that path.`, + headers: { + 'Content-Type': 'text/plain', + }, + }); + } + + const legacyConfig = readLegacyESConfig(); + const { hosts } = legacyConfig; + let esIncomingMessage: IncomingMessage; + + for (let idx = 0; idx < hosts.length; ++idx) { + const host = hosts[idx]; + try { + const uri = toURL(host, path); + + // Because this can technically be provided by a settings-defined proxy config, we need to + // preserve these property names to maintain BWC. + const { timeout, agent, headers, rejectUnauthorized } = getRequestConfig( + request.headers, + legacyConfig, + proxyConfigCollection, + uri.toString() + ); + + const requestHeaders = { + ...headers, + ...getProxyHeaders(request), + }; + + esIncomingMessage = await proxyRequest({ + method: method.toLowerCase() as any, + headers: requestHeaders, + uri, + timeout, + payload: body, + rejectUnauthorized, + agent, + }); + + break; + } catch (e) { + log.error(e); + if (e.code !== 'ECONNREFUSED') { + return response.internalError(e); + } + if (idx === hosts.length - 1) { + log.warn(`Could not connect to any configured ES node [${hosts.join(', ')}]`); + return response.customError({ + statusCode: 502, + body: e, + }); + } + // Otherwise, try the next host... + } + } + + const { + statusCode, + statusMessage, + headers: { warning }, + } = esIncomingMessage!; + + if (method.toUpperCase() !== 'HEAD') { + return response.custom({ + statusCode: statusCode!, + body: esIncomingMessage!, + headers: { + warning: warning || '', + }, + }); + } + + return response.custom({ + statusCode: statusCode!, + body: `${statusCode} - ${statusMessage}`, + headers: { + warning: warning || '', + 'Content-Type': 'text/plain', + }, + }); +}; diff --git a/src/plugins/console/server/routes/api/console/proxy/index.ts b/src/plugins/console/server/routes/api/console/proxy/index.ts new file mode 100644 index 00000000000000..5f7df1d7cf66b3 --- /dev/null +++ b/src/plugins/console/server/routes/api/console/proxy/index.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IRouter } from 'kibana/server'; +import { routeValidationConfig } from './validation_config'; +import { createHandler, CreateHandlerDependencies } from './create_handler'; + +export const registerProxyRoute = ( + deps: { + router: IRouter; + } & CreateHandlerDependencies +) => { + const { router, ...handlerDeps } = deps; + router.post( + { + path: '/api/console/proxy', + options: { + tags: ['access:console'], + body: { + output: 'stream', + parse: false, + }, + }, + validate: routeValidationConfig, + }, + createHandler(handlerDeps) + ); +}; diff --git a/src/plugins/console/server/routes/api/console/proxy/validation_config.ts b/src/plugins/console/server/routes/api/console/proxy/validation_config.ts new file mode 100644 index 00000000000000..f2372e9ee80d06 --- /dev/null +++ b/src/plugins/console/server/routes/api/console/proxy/validation_config.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { schema, TypeOf } from '@kbn/config-schema'; + +export type Query = TypeOf; +export type Body = TypeOf; + +const acceptedHttpVerb = schema.string({ + validate: method => { + return ['HEAD', 'GET', 'POST', 'PUT', 'DELETE'].some( + verb => verb.toLowerCase() === method.toLowerCase() + ) + ? undefined + : `Method must be one of, case insensitive ['HEAD', 'GET', 'POST', 'PUT', 'DELETE']. Received '${method}'.`; + }, +}); + +const nonEmptyString = schema.string({ + validate: s => (s === '' ? 'Expected non-empty string' : undefined), +}); + +export const routeValidationConfig = { + query: schema.object({ + method: acceptedHttpVerb, + path: nonEmptyString, + }), + body: schema.stream(), +}; diff --git a/src/plugins/console/server/routes/api/console/spec_definitions/index.ts b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts new file mode 100644 index 00000000000000..e2ece37f407acf --- /dev/null +++ b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { schema, TypeOf } from '@kbn/config-schema'; +import { IRouter, RequestHandler } from 'kibana/server'; +import { resolveApi } from '../../../../lib/spec_definitions'; + +export const registerSpecDefinitionsRoute = ({ router }: { router: IRouter }) => { + const handler: RequestHandler> = async ( + ctx, + request, + response + ) => { + const { sense_version: version, apis } = request.query; + + return response.ok({ + body: resolveApi(version, apis.split(',')), + headers: { + 'Content-Type': 'application/json', + }, + }); + }; + + const validate = { + query: schema.object({ + sense_version: schema.string({ defaultValue: '' }), + apis: schema.string(), + }), + }; + + router.get({ path: '/api/console/api_server', validate }, handler); + router.post({ path: '/api/console/api_server', validate }, handler); +}; diff --git a/src/plugins/console/server/types.ts b/src/plugins/console/server/types.ts new file mode 100644 index 00000000000000..60ce56ad39fcd4 --- /dev/null +++ b/src/plugins/console/server/types.ts @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Duration } from 'moment'; +import { ConsoleServerPlugin } from './plugin'; + +/** @public */ +export type ConsoleSetup = ReturnType extends Promise + ? U + : ReturnType; + +/** @internal */ +export interface ESConfigForProxy { + hosts: string[]; + requestHeadersWhitelist: string[]; + customHeaders: Record; + requestTimeout: Duration; +} diff --git a/x-pack/index.js b/x-pack/index.js index 83a7b5540334f6..9ab6e2ee322d90 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -22,7 +22,6 @@ import { maps } from './legacy/plugins/maps'; import { licenseManagement } from './legacy/plugins/license_management'; import { indexManagement } from './legacy/plugins/index_management'; import { indexLifecycleManagement } from './legacy/plugins/index_lifecycle_management'; -import { consoleExtensions } from './legacy/plugins/console_extensions'; import { spaces } from './legacy/plugins/spaces'; import { kueryAutocompleteInitializer } from './legacy/plugins/kuery_autocomplete'; import { canvas } from './legacy/plugins/canvas'; @@ -65,7 +64,6 @@ module.exports = function(kibana) { canvas(kibana), licenseManagement(kibana), indexManagement(kibana), - consoleExtensions(kibana), indexLifecycleManagement(kibana), kueryAutocompleteInitializer(kibana), infra(kibana), diff --git a/x-pack/legacy/plugins/console_extensions/index.js b/x-pack/legacy/plugins/console_extensions/index.js deleted file mode 100644 index fd1b48f0fd6b15..00000000000000 --- a/x-pack/legacy/plugins/console_extensions/index.js +++ /dev/null @@ -1,47 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { join } from 'path'; -import { processors } from './spec/ingest'; - -export function consoleExtensions(kibana) { - return new kibana.Plugin({ - id: 'console_extensions', - require: ['kibana', 'console'], - isEnabled(config) { - return ( - config.get('console_extensions.enabled') && - config.has('console.enabled') && - config.get('console.enabled') - ); - }, - - config(Joi) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - - init: server => { - if ( - server.plugins.console && - server.plugins.console.addExtensionSpecFilePath && - server.plugins.console.addProcessorDefinition - ) { - const { addExtensionSpecFilePath, addProcessorDefinition } = server.plugins.console; - - addExtensionSpecFilePath(join(__dirname, 'spec/')); - - processors.forEach(processor => addProcessorDefinition(processor)); - } else { - console.warn( - 'Missing server.plugins.console.addExtensionSpecFilePath extension point.', - 'Cannot add xpack APIs to autocomplete.' - ); - } - }, - }); -} diff --git a/x-pack/plugins/console_extensions/kibana.json b/x-pack/plugins/console_extensions/kibana.json new file mode 100644 index 00000000000000..9411523d3f6ddb --- /dev/null +++ b/x-pack/plugins/console_extensions/kibana.json @@ -0,0 +1,8 @@ +{ + "id": "consoleExtensions", + "version": "1.0.0", + "kibanaVersion": "kibana", + "requiredPlugins": ["console"], + "server": true, + "ui": false +} diff --git a/x-pack/plugins/console_extensions/server/config.ts b/x-pack/plugins/console_extensions/server/config.ts new file mode 100644 index 00000000000000..c429e0fce13fae --- /dev/null +++ b/x-pack/plugins/console_extensions/server/config.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema, TypeOf } from '@kbn/config-schema'; + +export type ConfigType = TypeOf; + +export const config = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); diff --git a/x-pack/plugins/console_extensions/server/index.ts b/x-pack/plugins/console_extensions/server/index.ts new file mode 100644 index 00000000000000..7fc16d4507da92 --- /dev/null +++ b/x-pack/plugins/console_extensions/server/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { PluginInitializerContext, PluginConfigDescriptor } from 'kibana/server'; + +import { config as configSchema, ConfigType } from './config'; +import { ConsoleExtensionsServerPlugin } from './plugin'; + +export const plugin = (ctx: PluginInitializerContext) => new ConsoleExtensionsServerPlugin(ctx); + +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; diff --git a/x-pack/plugins/console_extensions/server/plugin.ts b/x-pack/plugins/console_extensions/server/plugin.ts new file mode 100644 index 00000000000000..f4c41aa0a0ad54 --- /dev/null +++ b/x-pack/plugins/console_extensions/server/plugin.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { join } from 'path'; +import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server'; + +import { ConsoleSetup } from '../../../../src/plugins/console/server'; + +import { processors } from './spec/ingest/index'; + +interface SetupDependencies { + console: ConsoleSetup; +} + +export class ConsoleExtensionsServerPlugin implements Plugin { + log: Logger; + constructor(private readonly ctx: PluginInitializerContext) { + this.log = this.ctx.logger.get(); + } + + setup( + core: CoreSetup, + { console: { addProcessorDefinition, addExtensionSpecFilePath } }: SetupDependencies + ) { + addExtensionSpecFilePath(join(__dirname, 'spec/')); + processors.forEach(processor => addProcessorDefinition(processor)); + this.log.debug('Installed console autocomplete extensions.'); + } + start() {} +} diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.delete_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.delete_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.delete_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.delete_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.follow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.follow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow_info.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.follow_info.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow_info.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.follow_info.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.follow_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.follow_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.follow_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.forget_follower.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.forget_follower.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.forget_follower.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.forget_follower.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.get_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.get_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.get_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.get_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.pause_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.pause_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.pause_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.pause_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.pause_follow.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.pause_follow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.pause_follow.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.pause_follow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.put_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.put_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.put_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.put_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.resume_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.resume_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.resume_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.resume_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.resume_follow.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.resume_follow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.resume_follow.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.resume_follow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ccr.unfollow.json b/x-pack/plugins/console_extensions/server/spec/generated/ccr.unfollow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ccr.unfollow.json rename to x-pack/plugins/console_extensions/server/spec/generated/ccr.unfollow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/enrich.delete_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/enrich.delete_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/enrich.delete_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/enrich.delete_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/enrich.execute_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/enrich.execute_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/enrich.execute_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/enrich.execute_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/enrich.get_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/enrich.get_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/enrich.get_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/enrich.get_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/enrich.put_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/enrich.put_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/enrich.put_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/enrich.put_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/enrich.stats.json b/x-pack/plugins/console_extensions/server/spec/generated/enrich.stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/enrich.stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/enrich.stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/graph.explore.json b/x-pack/plugins/console_extensions/server/spec/generated/graph.explore.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/graph.explore.json rename to x-pack/plugins/console_extensions/server/spec/generated/graph.explore.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.delete_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.delete_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.delete_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.delete_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.explain_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.explain_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.explain_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.explain_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.get_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.get_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.get_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.get_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.get_status.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.get_status.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.get_status.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.get_status.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.move_to_step.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.move_to_step.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.move_to_step.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.move_to_step.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.put_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.put_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.put_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.put_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.remove_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.remove_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.remove_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.remove_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.retry.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.retry.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.retry.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.retry.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.set_policy.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.set_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.set_policy.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.set_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.start.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.start.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.start.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.start.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ilm.stop.json b/x-pack/plugins/console_extensions/server/spec/generated/ilm.stop.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ilm.stop.json rename to x-pack/plugins/console_extensions/server/spec/generated/ilm.stop.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/indices.freeze.json b/x-pack/plugins/console_extensions/server/spec/generated/indices.freeze.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/indices.freeze.json rename to x-pack/plugins/console_extensions/server/spec/generated/indices.freeze.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/indices.reload_search_analyzers.json b/x-pack/plugins/console_extensions/server/spec/generated/indices.reload_search_analyzers.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/indices.reload_search_analyzers.json rename to x-pack/plugins/console_extensions/server/spec/generated/indices.reload_search_analyzers.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/indices.unfreeze.json b/x-pack/plugins/console_extensions/server/spec/generated/indices.unfreeze.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/indices.unfreeze.json rename to x-pack/plugins/console_extensions/server/spec/generated/indices.unfreeze.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.delete.json b/x-pack/plugins/console_extensions/server/spec/generated/license.delete.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.delete.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.delete.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.get.json b/x-pack/plugins/console_extensions/server/spec/generated/license.get.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.get.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.get.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.get_basic_status.json b/x-pack/plugins/console_extensions/server/spec/generated/license.get_basic_status.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.get_basic_status.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.get_basic_status.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.get_trial_status.json b/x-pack/plugins/console_extensions/server/spec/generated/license.get_trial_status.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.get_trial_status.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.get_trial_status.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.post.json b/x-pack/plugins/console_extensions/server/spec/generated/license.post.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.post.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.post.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.post_start_basic.json b/x-pack/plugins/console_extensions/server/spec/generated/license.post_start_basic.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.post_start_basic.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.post_start_basic.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/license.post_start_trial.json b/x-pack/plugins/console_extensions/server/spec/generated/license.post_start_trial.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/license.post_start_trial.json rename to x-pack/plugins/console_extensions/server/spec/generated/license.post_start_trial.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/migration.deprecations.json b/x-pack/plugins/console_extensions/server/spec/generated/migration.deprecations.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/migration.deprecations.json rename to x-pack/plugins/console_extensions/server/spec/generated/migration.deprecations.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/migration.get_assistance.json b/x-pack/plugins/console_extensions/server/spec/generated/migration.get_assistance.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/migration.get_assistance.json rename to x-pack/plugins/console_extensions/server/spec/generated/migration.get_assistance.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/migration.upgrade.json b/x-pack/plugins/console_extensions/server/spec/generated/migration.upgrade.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/migration.upgrade.json rename to x-pack/plugins/console_extensions/server/spec/generated/migration.upgrade.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.close_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.close_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.close_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.close_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar_event.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar_event.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar_event.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar_event.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_calendar_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_calendar_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_expired_data.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_expired_data.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_expired_data.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_expired_data.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_filter.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_filter.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_filter.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_filter.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_forecast.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_forecast.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_forecast.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_forecast.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_model_snapshot.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_model_snapshot.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_model_snapshot.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_model_snapshot.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_trained_model.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.delete_trained_model.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.delete_trained_model.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.delete_trained_model.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.estimate_memory_usage.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.estimate_memory_usage.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.estimate_memory_usage.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.estimate_memory_usage.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.evaluate_data_frame.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.evaluate_data_frame.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.evaluate_data_frame.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.evaluate_data_frame.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.explain_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.explain_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.explain_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.explain_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.find_file_structure.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.find_file_structure.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.find_file_structure.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.find_file_structure.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.flush_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.flush_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.flush_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.flush_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.forecast.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.forecast.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.forecast.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.forecast.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_buckets.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_buckets.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_buckets.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_buckets.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_calendar_events.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_calendar_events.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_calendar_events.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_calendar_events.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_calendars.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_calendars.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_calendars.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_calendars.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_categories.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_categories.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_categories.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_categories.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_data_frame_analytics_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_data_frame_analytics_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_data_frame_analytics_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_data_frame_analytics_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_datafeed_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_datafeed_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_datafeed_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_datafeed_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_datafeeds.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_datafeeds.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_datafeeds.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_datafeeds.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_filters.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_filters.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_filters.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_filters.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_influencers.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_influencers.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_influencers.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_influencers.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_job_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_job_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_job_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_job_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_jobs.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_jobs.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_jobs.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_jobs.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_model_snapshots.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_model_snapshots.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_model_snapshots.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_model_snapshots.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_overall_buckets.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_overall_buckets.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_overall_buckets.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_overall_buckets.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_records.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_records.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_records.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_records.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_trained_models.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_trained_models.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_trained_models.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_trained_models.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_trained_models_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.get_trained_models_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.get_trained_models_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.get_trained_models_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.info.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.info.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.info.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.info.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.open_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.open_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.open_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.open_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.post_calendar_events.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.post_calendar_events.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.post_calendar_events.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.post_calendar_events.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.post_data.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.post_data.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.post_data.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.post_data.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.preview_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.preview_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.preview_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.preview_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_calendar.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_calendar.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_calendar.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_calendar.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_calendar_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_calendar_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_calendar_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_calendar_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_filter.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_filter.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_filter.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_filter.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_trained_model.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.put_trained_model.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.put_trained_model.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.put_trained_model.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.revert_model_snapshot.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.revert_model_snapshot.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.revert_model_snapshot.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.revert_model_snapshot.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.set_upgrade_mode.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.set_upgrade_mode.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.set_upgrade_mode.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.set_upgrade_mode.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.start_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.start_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.start_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.start_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.start_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.start_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.start_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.start_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.stop_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.stop_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.stop_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.stop_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.stop_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.stop_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.stop_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.stop_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_datafeed.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.update_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.update_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_filter.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.update_filter.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_filter.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.update_filter.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_job.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.update_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.update_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_model_snapshot.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.update_model_snapshot.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.update_model_snapshot.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.update_model_snapshot.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.upgrade.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.upgrade.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.upgrade.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.upgrade.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.validate.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.validate.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.validate.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.validate.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ml.validate_detector.json b/x-pack/plugins/console_extensions/server/spec/generated/ml.validate_detector.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ml.validate_detector.json rename to x-pack/plugins/console_extensions/server/spec/generated/ml.validate_detector.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/monitoring.bulk.json b/x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/monitoring.bulk.json rename to x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.delete_job.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.delete_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.delete_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.delete_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_jobs.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.get_jobs.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_jobs.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.get_jobs.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_rollup_caps.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.get_rollup_caps.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_rollup_caps.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.get_rollup_caps.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_rollup_index_caps.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.get_rollup_index_caps.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.get_rollup_index_caps.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.get_rollup_index_caps.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.put_job.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.put_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.put_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.put_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.rollup_search.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.rollup_search.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.rollup_search.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.rollup_search.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.start_job.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.start_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.start_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.start_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/rollup.stop_job.json b/x-pack/plugins/console_extensions/server/spec/generated/rollup.stop_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/rollup.stop_job.json rename to x-pack/plugins/console_extensions/server/spec/generated/rollup.stop_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.authenticate.json b/x-pack/plugins/console_extensions/server/spec/generated/security.authenticate.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.authenticate.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.authenticate.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.change_password.json b/x-pack/plugins/console_extensions/server/spec/generated/security.change_password.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.change_password.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.change_password.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.clear_cached_realms.json b/x-pack/plugins/console_extensions/server/spec/generated/security.clear_cached_realms.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.clear_cached_realms.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.clear_cached_realms.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.clear_cached_roles.json b/x-pack/plugins/console_extensions/server/spec/generated/security.clear_cached_roles.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.clear_cached_roles.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.clear_cached_roles.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.create_api_key.json b/x-pack/plugins/console_extensions/server/spec/generated/security.create_api_key.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.create_api_key.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.create_api_key.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.delete_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.delete_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_role.json b/x-pack/plugins/console_extensions/server/spec/generated/security.delete_role.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_role.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.delete_role.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_role_mapping.json b/x-pack/plugins/console_extensions/server/spec/generated/security.delete_role_mapping.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_role_mapping.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.delete_role_mapping.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_user.json b/x-pack/plugins/console_extensions/server/spec/generated/security.delete_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.delete_user.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.delete_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.disable_user.json b/x-pack/plugins/console_extensions/server/spec/generated/security.disable_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.disable_user.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.disable_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.enable_user.json b/x-pack/plugins/console_extensions/server/spec/generated/security.enable_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.enable_user.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.enable_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_api_key.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_api_key.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_api_key.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_api_key.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_builtin_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_builtin_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_builtin_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_builtin_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_role.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_role.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_role.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_role.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_role_mapping.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_role_mapping.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_role_mapping.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_role_mapping.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_token.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_token.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_user.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_user.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.get_user_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.get_user_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.get_user_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.get_user_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.has_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.has_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.has_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.has_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.invalidate_api_key.json b/x-pack/plugins/console_extensions/server/spec/generated/security.invalidate_api_key.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.invalidate_api_key.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.invalidate_api_key.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.invalidate_token.json b/x-pack/plugins/console_extensions/server/spec/generated/security.invalidate_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.invalidate_token.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.invalidate_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.put_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.put_privileges.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.put_role.json b/x-pack/plugins/console_extensions/server/spec/generated/security.put_role.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.put_role.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.put_role.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.put_role_mapping.json b/x-pack/plugins/console_extensions/server/spec/generated/security.put_role_mapping.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.put_role_mapping.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.put_role_mapping.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/security.put_user.json b/x-pack/plugins/console_extensions/server/spec/generated/security.put_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/security.put_user.json rename to x-pack/plugins/console_extensions/server/spec/generated/security.put_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.delete_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.delete_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.delete_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.delete_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.execute_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.execute_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.execute_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.execute_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.execute_retention.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.execute_retention.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.execute_retention.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.execute_retention.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.get_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.get_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.get_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.get_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_status.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.get_status.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.get_status.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.get_status.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.put_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.put_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.put_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.put_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.start.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.start.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.start.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.start.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/slm.stop.json b/x-pack/plugins/console_extensions/server/spec/generated/slm.stop.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/slm.stop.json rename to x-pack/plugins/console_extensions/server/spec/generated/slm.stop.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/sql.clear_cursor.json b/x-pack/plugins/console_extensions/server/spec/generated/sql.clear_cursor.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/sql.clear_cursor.json rename to x-pack/plugins/console_extensions/server/spec/generated/sql.clear_cursor.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/sql.query.json b/x-pack/plugins/console_extensions/server/spec/generated/sql.query.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/sql.query.json rename to x-pack/plugins/console_extensions/server/spec/generated/sql.query.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/sql.translate.json b/x-pack/plugins/console_extensions/server/spec/generated/sql.translate.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/sql.translate.json rename to x-pack/plugins/console_extensions/server/spec/generated/sql.translate.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/ssl.certificates.json b/x-pack/plugins/console_extensions/server/spec/generated/ssl.certificates.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/ssl.certificates.json rename to x-pack/plugins/console_extensions/server/spec/generated/ssl.certificates.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.delete_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.delete_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.delete_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.delete_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.get_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.get_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.get_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.get_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.get_transform_stats.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.get_transform_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.get_transform_stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.get_transform_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.preview_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.preview_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.preview_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.preview_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.put_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.put_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.put_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.put_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.start_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.start_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.start_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.start_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.stop_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.stop_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.stop_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.stop_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/transform.update_transform.json b/x-pack/plugins/console_extensions/server/spec/generated/transform.update_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/transform.update_transform.json rename to x-pack/plugins/console_extensions/server/spec/generated/transform.update_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.ack_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.ack_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.ack_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.ack_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.activate_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.activate_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.activate_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.activate_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.deactivate_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.deactivate_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.deactivate_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.deactivate_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.delete_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.delete_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.delete_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.delete_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.execute_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.execute_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.execute_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.execute_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.get_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.get_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.get_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.get_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.put_watch.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.put_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.put_watch.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.put_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.start.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.start.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.start.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.start.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.stats.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.stats.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/watcher.stop.json b/x-pack/plugins/console_extensions/server/spec/generated/watcher.stop.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/watcher.stop.json rename to x-pack/plugins/console_extensions/server/spec/generated/watcher.stop.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/xpack.info.json b/x-pack/plugins/console_extensions/server/spec/generated/xpack.info.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/xpack.info.json rename to x-pack/plugins/console_extensions/server/spec/generated/xpack.info.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/xpack.ssl.certificates.json b/x-pack/plugins/console_extensions/server/spec/generated/xpack.ssl.certificates.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/xpack.ssl.certificates.json rename to x-pack/plugins/console_extensions/server/spec/generated/xpack.ssl.certificates.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/generated/xpack.usage.json b/x-pack/plugins/console_extensions/server/spec/generated/xpack.usage.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/generated/xpack.usage.json rename to x-pack/plugins/console_extensions/server/spec/generated/xpack.usage.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/ingest/index.js b/x-pack/plugins/console_extensions/server/spec/ingest/index.ts similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/ingest/index.js rename to x-pack/plugins/console_extensions/server/spec/ingest/index.ts diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.follow.json b/x-pack/plugins/console_extensions/server/spec/overrides/ccr.follow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.follow.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ccr.follow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.forget_follower.json b/x-pack/plugins/console_extensions/server/spec/overrides/ccr.forget_follower.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.forget_follower.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ccr.forget_follower.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.put_auto_follow_pattern.json b/x-pack/plugins/console_extensions/server/spec/overrides/ccr.put_auto_follow_pattern.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.put_auto_follow_pattern.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ccr.put_auto_follow_pattern.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.resume_follow.json b/x-pack/plugins/console_extensions/server/spec/overrides/ccr.resume_follow.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ccr.resume_follow.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ccr.resume_follow.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/enrich.put_policy.json b/x-pack/plugins/console_extensions/server/spec/overrides/enrich.put_policy.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/enrich.put_policy.json rename to x-pack/plugins/console_extensions/server/spec/overrides/enrich.put_policy.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ilm.move_to_step.json b/x-pack/plugins/console_extensions/server/spec/overrides/ilm.move_to_step.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ilm.move_to_step.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ilm.move_to_step.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ilm.put_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/overrides/ilm.put_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ilm.put_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ilm.put_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.estimate_memory_usage.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.estimate_memory_usage.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.estimate_memory_usage.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.estimate_memory_usage.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.evaluate_data_frame.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.evaluate_data_frame.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.evaluate_data_frame.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.evaluate_data_frame.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.explain_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.explain_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.explain_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.explain_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_buckets.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_buckets.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_buckets.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_buckets.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_calendar_events.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_calendar_events.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_calendar_events.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_calendar_events.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_calendars.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_calendars.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_calendars.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_calendars.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_categories.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_categories.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_categories.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_categories.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_influencers.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_influencers.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_influencers.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_influencers.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_model_snapshots.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_model_snapshots.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_model_snapshots.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_model_snapshots.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_overall_buckets.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_overall_buckets.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_overall_buckets.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_overall_buckets.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_records.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.get_records.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.get_records.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.get_records.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.post_calendar_events.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.post_calendar_events.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.post_calendar_events.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.post_calendar_events.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_calendar.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.put_calendar.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_calendar.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.put_calendar.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_data_frame_analytics.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.put_data_frame_analytics.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_data_frame_analytics.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.put_data_frame_analytics.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_datafeed.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.put_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.put_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_job.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.put_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_job.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.put_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_trained_model.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.put_trained_model.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.put_trained_model.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.put_trained_model.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.revert_model_snapshot.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.revert_model_snapshot.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.revert_model_snapshot.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.revert_model_snapshot.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_datafeed.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.update_datafeed.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_datafeed.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.update_datafeed.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_job.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.update_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_job.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.update_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_model_snapshot.json b/x-pack/plugins/console_extensions/server/spec/overrides/ml.update_model_snapshot.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/ml.update_model_snapshot.json rename to x-pack/plugins/console_extensions/server/spec/overrides/ml.update_model_snapshot.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.authenticate.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.authenticate.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.authenticate.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.authenticate.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.change_password.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.change_password.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.change_password.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.change_password.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.create_api_key.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.create_api_key.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.create_api_key.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.create_api_key.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.delete_privileges.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.delete_privileges.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.get_token.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.get_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.get_token.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.get_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.has_privileges.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.has_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.has_privileges.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.has_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.invalidate_api_key.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.invalidate_api_key.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.invalidate_api_key.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.invalidate_api_key.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.invalidate_token.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.invalidate_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.invalidate_token.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.invalidate_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_privileges.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_privileges.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_role.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_role.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_role.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.put_role.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_role_mapping.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_role_mapping.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_role_mapping.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.put_role_mapping.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_user.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/security.put_user.json rename to x-pack/plugins/console_extensions/server/spec/overrides/security.put_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/slm.put_lifecycle.json b/x-pack/plugins/console_extensions/server/spec/overrides/slm.put_lifecycle.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/slm.put_lifecycle.json rename to x-pack/plugins/console_extensions/server/spec/overrides/slm.put_lifecycle.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/slm.start.json b/x-pack/plugins/console_extensions/server/spec/overrides/slm.start.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/slm.start.json rename to x-pack/plugins/console_extensions/server/spec/overrides/slm.start.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/slm.stop.json b/x-pack/plugins/console_extensions/server/spec/overrides/slm.stop.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/slm.stop.json rename to x-pack/plugins/console_extensions/server/spec/overrides/slm.stop.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/sql.query.json b/x-pack/plugins/console_extensions/server/spec/overrides/sql.query.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/sql.query.json rename to x-pack/plugins/console_extensions/server/spec/overrides/sql.query.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/transform.get_transform_stats.json b/x-pack/plugins/console_extensions/server/spec/overrides/transform.get_transform_stats.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/transform.get_transform_stats.json rename to x-pack/plugins/console_extensions/server/spec/overrides/transform.get_transform_stats.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/transform.preview_transform.json b/x-pack/plugins/console_extensions/server/spec/overrides/transform.preview_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/transform.preview_transform.json rename to x-pack/plugins/console_extensions/server/spec/overrides/transform.preview_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/transform.put_transform.json b/x-pack/plugins/console_extensions/server/spec/overrides/transform.put_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/transform.put_transform.json rename to x-pack/plugins/console_extensions/server/spec/overrides/transform.put_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/transform.stop_transform.json b/x-pack/plugins/console_extensions/server/spec/overrides/transform.stop_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/transform.stop_transform.json rename to x-pack/plugins/console_extensions/server/spec/overrides/transform.stop_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/transform.update_transform.json b/x-pack/plugins/console_extensions/server/spec/overrides/transform.update_transform.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/transform.update_transform.json rename to x-pack/plugins/console_extensions/server/spec/overrides/transform.update_transform.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.graph.explore.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.graph.explore.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.graph.explore.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.graph.explore.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.info.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.info.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.info.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.info.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.license.post.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.license.post.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.license.post.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.license.post.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.delete_job.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.delete_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.delete_job.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.delete_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.put_job.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.put_job.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.put_job.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.put_job.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.rollup_search.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.rollup_search.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.rollup.rollup_search.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.rollup.rollup_search.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.authenticate.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.authenticate.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.authenticate.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.authenticate.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.change_password.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.change_password.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.change_password.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.change_password.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.get_token.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.get_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.get_token.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.get_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.invalidate_token.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.invalidate_token.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.invalidate_token.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.invalidate_token.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_role.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_role.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_role.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_role.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_role_mapping.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_role_mapping.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_role_mapping.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_role_mapping.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_user.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_user.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.security.put_user.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.security.put_user.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.watcher.execute_watch.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.watcher.execute_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.watcher.execute_watch.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.watcher.execute_watch.json diff --git a/x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.watcher.put_watch.json b/x-pack/plugins/console_extensions/server/spec/overrides/xpack.watcher.put_watch.json similarity index 100% rename from x-pack/legacy/plugins/console_extensions/spec/overrides/xpack.watcher.put_watch.json rename to x-pack/plugins/console_extensions/server/spec/overrides/xpack.watcher.put_watch.json From 395e7b6907fc68a47a1396e0ccc40510814e34a1 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 30 Jan 2020 11:09:12 +0100 Subject: [PATCH 07/69] =?UTF-8?q?[Bugfix][State=20Management]=20'state:sto?= =?UTF-8?q?reInSessionStorage'=20doesn=E2=80=99t=20take=20effect=20for=20d?= =?UTF-8?q?ashboard=20without=20full=20page=20reload=20(#56284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bugfix: 'state:storeInSessionStorage' doesn’t take effect for dashboard without full page reload * add test “changing 'state:storeInSessionStorage' also takes effect without full page reload” --- .../public/dashboard/np_ready/application.ts | 5 +--- .../dashboard/np_ready/dashboard_app.tsx | 8 +++++- .../np_ready/dashboard_app_controller.tsx | 9 ++++++- .../public/dashboard/np_ready/legacy_app.js | 17 ++++++++++--- .../kibana/public/dashboard/plugin.ts | 11 +------- .../apps/management/_kibana_settings.js | 25 ++++++++++++------- 6 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts index d9c05796380477..1a0a99311d06b0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts @@ -19,7 +19,6 @@ import { EuiConfirmModal, EuiIcon } from '@elastic/eui'; import angular, { IModule } from 'angular'; -import { History } from 'history'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext, @@ -28,7 +27,7 @@ import { LegacyCoreStart, SavedObjectsClientContract, } from 'kibana/public'; -import { IKbnUrlStateStorage, Storage } from '../../../../../../plugins/kibana_utils/public'; +import { Storage } from '../../../../../../plugins/kibana_utils/public'; import { configureAppAngularModule, confirmModalFactory, @@ -66,8 +65,6 @@ export interface RenderDeps { embeddables: IEmbeddableStart; localStorage: Storage; share: SharePluginStart; - history: History; - kbnUrlStateStorage: IKbnUrlStateStorage; } let angularModuleInstance: IModule | null = null; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx index 367db6644ff57b..a48c165116304f 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx @@ -19,6 +19,7 @@ import moment from 'moment'; import { Subscription } from 'rxjs'; +import { History } from 'history'; import { IInjector } from '../legacy_imports'; @@ -35,6 +36,7 @@ import { import { DashboardAppController } from './dashboard_app_controller'; import { RenderDeps } from './application'; +import { IKbnUrlStateStorage } from '../../../../../../plugins/kibana_utils/public/'; export interface DashboardAppScope extends ng.IScope { dash: SavedObjectDashboard; @@ -96,7 +98,9 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) { $route: any, $routeParams: { id?: string; - } + }, + kbnUrlStateStorage: IKbnUrlStateStorage, + history: History ) => new DashboardAppController({ $route, @@ -105,6 +109,8 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) { config, confirmModal, indexPatterns: deps.npDataStart.indexPatterns, + kbnUrlStateStorage, + history, ...deps, }), }; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index e85054cd7fb34f..a8eec9c2504a7c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -24,6 +24,7 @@ import angular from 'angular'; import { Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; +import { History } from 'history'; import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen'; import { @@ -77,7 +78,11 @@ import { SavedObjectFinderProps, SavedObjectFinderUi, } from '../../../../../../plugins/kibana_react/public'; -import { removeQueryParam, unhashUrl } from '../../../../../../plugins/kibana_utils/public'; +import { + IKbnUrlStateStorage, + removeQueryParam, + unhashUrl, +} from '../../../../../../plugins/kibana_utils/public'; export interface DashboardAppControllerDependencies extends RenderDeps { $scope: DashboardAppScope; @@ -87,6 +92,8 @@ export interface DashboardAppControllerDependencies extends RenderDeps { dashboardConfig: any; config: any; confirmModal: ConfirmModalFn; + history: History; + kbnUrlStateStorage: IKbnUrlStateStorage; } export class DashboardAppController { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js index 7ba404d52d9a61..2121b51ea78d85 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js @@ -21,11 +21,13 @@ import { i18n } from '@kbn/i18n'; import dashboardTemplate from './dashboard_app.html'; import dashboardListingTemplate from './listing/dashboard_listing_ng_wrapper.html'; +import { createHashHistory } from 'history'; import { ensureDefaultIndexPattern } from '../legacy_imports'; import { initDashboardAppDirective } from './dashboard_app'; import { createDashboardEditUrl, DashboardConstants } from './dashboard_constants'; import { + createKbnUrlStateStorage, InvalidJSONProperty, SavedObjectNotFound, } from '../../../../../../plugins/kibana_utils/public'; @@ -62,6 +64,14 @@ export function initDashboardApp(app, deps) { stateManagementConfigProvider.disable(); }); + app.factory('history', () => createHashHistory()); + app.factory('kbnUrlStateStorage', history => + createKbnUrlStateStorage({ + history, + useHash: deps.uiSettings.get('state:storeInSessionStorage'), + }) + ); + app.config(function($routeProvider) { const defaults = { reloadOnSearch: false, @@ -87,7 +97,7 @@ export function initDashboardApp(app, deps) { .when(DashboardConstants.LANDING_PAGE_PATH, { ...defaults, template: dashboardListingTemplate, - controller($injector, $location, $scope) { + controller($injector, $location, $scope, kbnUrlStateStorage) { const service = deps.savedDashboards; const kbnUrl = $injector.get('kbnUrl'); const dashboardConfig = deps.dashboardConfig; @@ -95,7 +105,7 @@ export function initDashboardApp(app, deps) { // syncs `_g` portion of url with query services const { stop: stopSyncingGlobalStateWithUrl } = syncQuery( deps.npDataStart.query, - deps.kbnUrlStateStorage + kbnUrlStateStorage ); $scope.listingLimit = deps.uiSettings.get('savedObjects:listingLimit'); @@ -189,7 +199,7 @@ export function initDashboardApp(app, deps) { template: dashboardTemplate, controller: createNewDashboardCtrl, resolve: { - dash: function($rootScope, $route, redirectWhenMissing, kbnUrl) { + dash: function($rootScope, $route, redirectWhenMissing, kbnUrl, history) { const id = $route.current.params.id; return ensureDefaultIndexPattern(deps.core, deps.npDataStart, $rootScope, kbnUrl) @@ -216,7 +226,6 @@ export function initDashboardApp(app, deps) { // See https://github.com/elastic/kibana/issues/10951 for more context. if (error instanceof SavedObjectNotFound && id === 'create') { // Note preserve querystring part is necessary so the state is preserved through the redirect. - const history = deps.history; history.replace({ ...history.location, // preserve query, pathname: DashboardConstants.CREATE_NEW_DASHBOARD_URL, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts index 732fbd525ae373..ca4b18a37504c6 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts @@ -25,13 +25,12 @@ import { Plugin, SavedObjectsClientContract, } from 'kibana/public'; -import { createHashHistory } from 'history'; import { i18n } from '@kbn/i18n'; import { RenderDeps } from './np_ready/application'; import { DataStart } from '../../../data/public'; import { DataPublicPluginStart as NpDataStart } from '../../../../../plugins/data/public'; import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; -import { createKbnUrlStateStorage, Storage } from '../../../../../plugins/kibana_utils/public'; +import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { DashboardConstants } from './np_ready/dashboard_constants'; import { @@ -97,12 +96,6 @@ export class DashboardPlugin implements Plugin { overlays: contextCore.overlays, }); - const history = createHashHistory(); - const kbnUrlStateStorage = createKbnUrlStateStorage({ - history, - useHash: core.uiSettings.get('state:storeInSessionStorage'), - }); - const deps: RenderDeps = { core: contextCore as LegacyCoreStart, ...angularDependencies, @@ -118,8 +111,6 @@ export class DashboardPlugin implements Plugin { embeddables, dashboardCapabilities: contextCore.application.capabilities.dashboard, localStorage: new Storage(localStorage), - history, - kbnUrlStateStorage, }; const { renderApp } = await import('./np_ready/application'); return renderApp(params.element, params.appBasePath, deps); diff --git a/test/functional/apps/management/_kibana_settings.js b/test/functional/apps/management/_kibana_settings.js index 2dc5c395a605f3..c99368ba4e8599 100644 --- a/test/functional/apps/management/_kibana_settings.js +++ b/test/functional/apps/management/_kibana_settings.js @@ -22,7 +22,7 @@ import expect from '@kbn/expect'; export default function({ getService, getPageObjects }) { const kibanaServer = getService('kibanaServer'); const browser = getService('browser'); - const PageObjects = getPageObjects(['settings', 'common', 'dashboard', 'timePicker']); + const PageObjects = getPageObjects(['settings', 'common', 'dashboard', 'timePicker', 'header']); describe('kibana settings', function describeIndexTests() { before(async function() { @@ -94,14 +94,21 @@ export default function({ getService, getPageObjects }) { expect(appState.length).to.be.lessThan(20); }); - after( - 'navigate to settings page and turn state:storeInSessionStorage back to false', - async () => { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaSettings(); - await PageObjects.settings.toggleAdvancedSettingCheckbox('state:storeInSessionStorage'); - } - ); + it("changing 'state:storeInSessionStorage' also takes effect without full page reload", async () => { + await PageObjects.dashboard.preserveCrossAppState(); + await PageObjects.header.clickStackManagement(); + await PageObjects.settings.clickKibanaSettings(); + await PageObjects.settings.toggleAdvancedSettingCheckbox('state:storeInSessionStorage'); + await PageObjects.header.clickDashboard(); + const currentUrl = await browser.getCurrentUrl(); + const urlPieces = currentUrl.match(/(.*)?_g=(.*)&_a=(.*)/); + const globalState = urlPieces[2]; + const appState = urlPieces[3]; + // We don't have to be exact, just need to ensure it's greater than when the hashed variation is being used, + // which is less than 20 characters. + expect(globalState.length).to.be.greaterThan(20); + expect(appState.length).to.be.greaterThan(20); + }); }); after(async function() { From 3e2e783a8de4d537fcaca1898d05d247f27df2e8 Mon Sep 17 00:00:00 2001 From: Daniil Suleiman <31325372+sulemanof@users.noreply.github.com> Date: Thu, 30 Jan 2020 13:50:49 +0300 Subject: [PATCH 08/69] [Vis: Default Editor] Fix advanced params rendering (#56295) * Fix advanced params rendering * Use EuiSpacer for margin --- .../__snapshots__/agg_params.test.tsx.snap | 58 +++++++++---------- .../public/components/agg_params.tsx | 7 ++- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg_params.test.tsx.snap b/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg_params.test.tsx.snap index 1275a52eead577..028d0b80166930 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg_params.test.tsx.snap +++ b/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg_params.test.tsx.snap @@ -38,39 +38,33 @@ exports[`DefaultEditorAggParams component should init with the default set of pa setAggParamValue={[MockFunction]} showValidation={false} /> - + - - - + - - + } + formIsTouched={false} + key="jsonundefined" + onChangeParamsState={[Function]} + setAggParamValue={[MockFunction]} + showValidation={false} + /> + `; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx index 0d83860a1475a3..47e98f175ab73f 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx @@ -18,7 +18,7 @@ */ import React, { useCallback, useReducer, useEffect, useMemo } from 'react'; -import { EuiForm, EuiAccordion, EuiSpacer, EuiFormRow } from '@elastic/eui'; +import { EuiForm, EuiAccordion, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import useUnmount from 'react-use/lib/useUnmount'; @@ -219,7 +219,8 @@ function DefaultEditorAggParams({ })} {params.advanced.length ? ( - + <> + - + ) : null} ); From a8622cfcd8d190686998c4cbaee36bb3f66099d3 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 30 Jan 2020 12:10:30 +0100 Subject: [PATCH 09/69] [Uptime] Use dynamic index pattern in Uptime (#55446) * Using auto attribute field and fixed title * added constant * refactor index pattern state * fixed type * PR feedback * resolve conflcits Co-authored-by: Elastic Machine --- .../filter_group/filter_group_container.tsx | 93 +++++++++++++++++++ .../public/components/connected/index.ts | 3 + .../kuerybar/kuery_bar_container.tsx | 21 +++++ .../connected/pages/overview_container.ts | 14 +++ ...w_page_parsing_error_callout.test.tsx.snap | 10 ++ .../functional/filter_group/filter_group.tsx | 92 ++---------------- .../functional/filter_group/index.ts | 2 +- .../public/components/functional/index.ts | 3 +- .../kuery_bar/{index.tsx => kuery_bar.tsx} | 19 ++-- .../overview_page_parsing_error_callout.tsx | 1 + .../plugins/uptime/public/hooks/index.ts | 2 +- .../public/hooks/update_kuery_string.ts | 65 +++++++++++++ .../uptime/public/hooks/use_index_pattern.ts | 21 ----- .../to_static_index_pattern.test.ts.snap | 19 ---- .../__tests__/to_static_index_pattern.test.ts | 19 ---- .../helper/combine_filters_and_user_search.ts | 3 + .../plugins/uptime/public/lib/helper/index.ts | 1 - .../lib/helper/to_static_index_pattern.ts | 11 --- .../plugins/uptime/public/pages/index.ts | 2 +- .../plugins/uptime/public/pages/overview.tsx | 81 ++++------------ .../legacy/plugins/uptime/public/routes.tsx | 2 +- .../uptime/public/state/actions/index.ts | 1 + .../public/state/actions/index_patternts.ts | 12 +++ .../plugins/uptime/public/state/api/index.ts | 1 + .../uptime/public/state/api/index_pattern.ts | 21 +++++ .../uptime/public/state/effects/index.ts | 2 + .../public/state/effects/index_pattern.ts | 17 ++++ .../uptime/public/state/reducers/index.ts | 2 + .../public/state/reducers/index_pattern.ts | 41 ++++++++ .../state/selectors/__tests__/index.test.ts | 5 + .../uptime/public/state/selectors/index.ts | 4 + .../lib/adapters/framework/adapter_types.ts | 14 --- .../uptime/server/lib/adapters/index.ts | 2 +- .../heartbeat_index_pattern.json | 13 --- .../kibana_saved_objects_adapter.ts | 25 ----- .../lib/adapters/saved_objects/types.ts | 11 --- .../index.ts | 3 +- .../stub_index_pattern/stub_index_pattern.ts | 54 +++++++++++ .../uptime/server/lib/compose/kibana.ts | 4 +- .../legacy/plugins/uptime/server/lib/lib.ts | 4 +- .../index_pattern/get_index_pattern.ts | 4 +- 41 files changed, 420 insertions(+), 304 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts rename x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/{index.tsx => kuery_bar.tsx} (91%) create mode 100644 x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts delete mode 100644 x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts delete mode 100644 x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/to_static_index_pattern.test.ts.snap delete mode 100644 x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/to_static_index_pattern.test.ts delete mode 100644 x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/heartbeat_index_pattern.json delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts rename x-pack/legacy/plugins/uptime/server/lib/adapters/{saved_objects => stub_index_pattern}/index.ts (67%) create mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/stub_index_pattern.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx new file mode 100644 index 00000000000000..2d1c21d1c997da --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { useUrlParams } from '../../../hooks'; +import { parseFiltersMap } from '../../functional/filter_group/parse_filter_map'; +import { AppState } from '../../../state'; +import { fetchOverviewFilters, GetOverviewFiltersPayload } from '../../../state/actions'; +import { FilterGroupComponent } from '../../functional/filter_group'; +import { OverviewFilters } from '../../../../common/runtime_types/overview_filters'; + +interface OwnProps { + esFilters?: string; +} + +interface StoreProps { + esKuery: string; + lastRefresh: number; + loading: boolean; + overviewFilters: OverviewFilters; +} + +interface DispatchProps { + loadFilterGroup: typeof fetchOverviewFilters; +} + +type Props = OwnProps & StoreProps & DispatchProps; + +export const Container: React.FC = ({ + esKuery, + esFilters, + loading, + loadFilterGroup, + overviewFilters, +}: Props) => { + const [getUrlParams, updateUrl] = useUrlParams(); + + const { dateRangeStart, dateRangeEnd, statusFilter, filters: urlFilters } = getUrlParams(); + + useEffect(() => { + const filterSelections = parseFiltersMap(urlFilters); + loadFilterGroup({ + dateRangeStart, + dateRangeEnd, + locations: filterSelections.locations ?? [], + ports: filterSelections.ports ?? [], + schemes: filterSelections.schemes ?? [], + search: esKuery, + statusFilter, + tags: filterSelections.tags ?? [], + }); + }, [dateRangeStart, dateRangeEnd, esKuery, esFilters, statusFilter, urlFilters, loadFilterGroup]); + + // update filters in the URL from filter group + const onFilterUpdate = (filtersKuery: string) => { + if (urlFilters !== filtersKuery) { + updateUrl({ filters: filtersKuery, pagination: '' }); + } + }; + + return ( + + ); +}; + +const mapStateToProps = ({ + overviewFilters: { loading, filters }, + ui: { esKuery, lastRefresh }, +}: AppState): StoreProps => ({ + esKuery, + overviewFilters: filters, + lastRefresh, + loading, +}); + +const mapDispatchToProps = (dispatch: any): DispatchProps => ({ + loadFilterGroup: (payload: GetOverviewFiltersPayload) => dispatch(fetchOverviewFilters(payload)), +}); + +export const FilterGroup = connect( + // @ts-ignore connect is expecting null | undefined for some reason + mapStateToProps, + mapDispatchToProps +)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/index.ts b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts index f9f6aa263ed270..5bb0d1ae8468f9 100644 --- a/x-pack/legacy/plugins/uptime/public/components/connected/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts @@ -5,3 +5,6 @@ */ export { PingHistogram } from './charts/ping_histogram'; +export { KueryBar } from './kuerybar/kuery_bar_container'; +export { OverviewPage } from './pages/overview_container'; +export { FilterGroup } from './filter_group/filter_group_container'; diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx new file mode 100644 index 00000000000000..d0f160b2c55403 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { connect } from 'react-redux'; +import { AppState } from '../../../state'; +import { selectIndexPattern } from '../../../state/selectors'; +import { getIndexPattern } from '../../../state/actions'; +import { KueryBarComponent } from '../../functional'; + +const mapStateToProps = (state: AppState) => ({ indexPattern: selectIndexPattern(state) }); + +const mapDispatchToProps = (dispatch: any) => ({ + loadIndexPattern: () => { + dispatch(getIndexPattern({})); + }, +}); + +export const KueryBar = connect(mapStateToProps, mapDispatchToProps)(KueryBarComponent); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts b/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts new file mode 100644 index 00000000000000..406fab8f5bf010 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { connect } from 'react-redux'; +import { OverviewPageComponent } from '../../../pages/overview'; +import { selectIndexPattern } from '../../../state/selectors'; +import { AppState } from '../../../state'; + +const mapStateToProps = (state: AppState) => ({ indexPattern: selectIndexPattern(state) }); + +export const OverviewPage = connect(mapStateToProps)(OverviewPageComponent); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/overview_page_parsing_error_callout.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/overview_page_parsing_error_callout.test.tsx.snap index 4b9c169b3d9b33..653b739145f305 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/overview_page_parsing_error_callout.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/overview_page_parsing_error_callout.test.tsx.snap @@ -4,6 +4,11 @@ exports[`OverviewPageParsingErrorCallout renders without errors when a valid err

    @@ -26,6 +31,11 @@ exports[`OverviewPageParsingErrorCallout renders without errors when an error wi

    diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/filter_group.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/filter_group.tsx index 351302fb383561..ff73554c8f07c8 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/filter_group.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/filter_group.tsx @@ -4,44 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; import { EuiFilterGroup } from '@elastic/eui'; -import React, { useEffect } from 'react'; import { i18n } from '@kbn/i18n'; -import { connect } from 'react-redux'; import { FilterPopoverProps, FilterPopover } from './filter_popover'; import { FilterStatusButton } from './filter_status_button'; -import { OverviewFilters } from '../../../../common/runtime_types'; -import { fetchOverviewFilters, GetOverviewFiltersPayload } from '../../../state/actions'; -import { AppState } from '../../../state'; -import { useUrlParams } from '../../../hooks'; -import { parseFiltersMap } from './parse_filter_map'; +import { OverviewFilters } from '../../../../common/runtime_types/overview_filters'; -interface OwnProps { - currentFilter: any; - onFilterUpdate: any; - dateRangeStart: string; - dateRangeEnd: string; - filters?: string; - statusFilter?: string; -} - -interface StoreProps { - esKuery: string; - lastRefresh: number; +interface PresentationalComponentProps { loading: boolean; overviewFilters: OverviewFilters; + currentFilter: string; + onFilterUpdate: (filtersKuery: string) => void; } -interface DispatchProps { - loadFilterGroup: typeof fetchOverviewFilters; -} - -type Props = OwnProps & StoreProps & DispatchProps; - -type PresentationalComponentProps = Pick & - Pick; - -export const PresentationalComponent: React.FC = ({ +export const FilterGroupComponent: React.FC = ({ currentFilter, overviewFilters, loading, @@ -151,60 +128,3 @@ export const PresentationalComponent: React.FC = ( ); }; - -export const Container: React.FC = ({ - currentFilter, - esKuery, - filters, - loading, - loadFilterGroup, - dateRangeStart, - dateRangeEnd, - overviewFilters, - statusFilter, - onFilterUpdate, -}: Props) => { - const [getUrlParams] = useUrlParams(); - const { filters: urlFilters } = getUrlParams(); - useEffect(() => { - const filterSelections = parseFiltersMap(urlFilters); - loadFilterGroup({ - dateRangeStart, - dateRangeEnd, - locations: filterSelections.locations ?? [], - ports: filterSelections.ports ?? [], - schemes: filterSelections.schemes ?? [], - search: esKuery, - statusFilter, - tags: filterSelections.tags ?? [], - }); - }, [dateRangeStart, dateRangeEnd, esKuery, filters, statusFilter, urlFilters, loadFilterGroup]); - return ( - - ); -}; - -const mapStateToProps = ({ - overviewFilters: { loading, filters }, - ui: { esKuery, lastRefresh }, -}: AppState): StoreProps => ({ - esKuery, - overviewFilters: filters, - lastRefresh, - loading, -}); - -const mapDispatchToProps = (dispatch: any): DispatchProps => ({ - loadFilterGroup: (payload: GetOverviewFiltersPayload) => dispatch(fetchOverviewFilters(payload)), -}); - -export const FilterGroup = connect( - // @ts-ignore connect is expecting null | undefined for some reason - mapStateToProps, - mapDispatchToProps -)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/index.ts index 285972fb34eaac..2aae026144d8f8 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/filter_group/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { FilterGroup } from './filter_group'; +export { FilterGroupComponent } from './filter_group'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts index b9f0014322062d..6af17cfd67c462 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts @@ -7,9 +7,8 @@ export { DonutChart } from './charts/donut_chart'; export { EmptyState } from './empty_state'; export { MonitorStatusBar } from './monitor_status_details'; -export { FilterGroup } from './filter_group'; export { IntegrationLink } from './integration_link'; -export { KueryBar } from './kuery_bar'; +export { KueryBarComponent } from './kuery_bar/kuery_bar'; export { MonitorCharts } from './monitor_charts'; export { MonitorList } from './monitor_list'; export { OverviewPageParsingErrorCallout } from './overview_page_parsing_error_callout'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx similarity index 91% rename from x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx rename to x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx index 679106f7e19b4d..63c8885fe5864a 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx @@ -11,14 +11,12 @@ import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import { Typeahead } from './typeahead'; import { useUrlParams } from '../../../hooks'; -import { toStaticIndexPattern } from '../../../lib/helper'; import { esKuery, IIndexPattern, autocomplete, DataPublicPluginStart, } from '../../../../../../../../src/plugins/data/public'; -import { useIndexPattern } from '../../../hooks'; const Container = styled.div` margin-bottom: 10px; @@ -36,20 +34,29 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { interface Props { autocomplete: DataPublicPluginStart['autocomplete']; + loadIndexPattern: any; + indexPattern: any; } -export function KueryBar({ autocomplete: autocompleteService }: Props) { +export function KueryBarComponent({ + autocomplete: autocompleteService, + loadIndexPattern, + indexPattern, +}: Props) { + useEffect(() => { + if (!indexPattern) { + loadIndexPattern(); + } + }, [indexPattern, loadIndexPattern]); + const [state, setState] = useState({ suggestions: [], isLoadingIndexPattern: true, }); - const [indexPattern, setIndexPattern] = useState(undefined); const [isLoadingIndexPattern, setIsLoadingIndexPattern] = useState(true); const [isLoadingSuggestions, setIsLoadingSuggestions] = useState(false); let currentRequestCheck: string; - useIndexPattern((result: any) => setIndexPattern(toStaticIndexPattern(result))); - useEffect(() => { if (indexPattern !== undefined) { setIsLoadingIndexPattern(false); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/overview_page_parsing_error_callout.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/overview_page_parsing_error_callout.tsx index 3d38ce42dd1f0b..b71a4f2f8646a5 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/overview_page_parsing_error_callout.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/overview_page_parsing_error_callout.tsx @@ -26,6 +26,7 @@ export const OverviewPageParsingErrorCallout = ({ })} color="danger" iconType="alert" + style={{ width: '100%' }} >

    { + // Update EsQuery in Redux to be used in FilterGroup + const searchDSL: string = filterQueryString + ? JSON.stringify( + esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(filterQueryString), indexPattern) + ) + : ''; + store.dispatch(setEsKueryString(searchDSL)); +}; + +const getKueryString = (urlFilters: string): string => { + let kueryString = ''; + // We are using try/catch here because this is user entered value + // and JSON.parse and stringifyKueries can have hard time parsing + // all possible scenarios, we can safely ignore if we can't parse them + try { + if (urlFilters !== '') { + const filterMap = new Map>(JSON.parse(urlFilters)); + kueryString = stringifyKueries(filterMap); + } + } catch { + kueryString = ''; + } + return kueryString; +}; + +export const useUpdateKueryString = ( + indexPattern: IIndexPattern, + filterQueryString = '', + urlFilters: string +): [string?, Error?] => { + const kueryString = getKueryString(urlFilters); + + const combinedFilterString = combineFiltersAndUserSearch(filterQueryString, kueryString); + + let esFilters: string | undefined; + // this try catch is necessary to evaluate user input in kuery bar, + // this error will be actually shown in UI for user to see + try { + if ((filterQueryString || urlFilters) && indexPattern) { + const ast = esKuery.fromKueryExpression(combinedFilterString); + + const elasticsearchQuery = esKuery.toElasticsearchQuery(ast, indexPattern); + + esFilters = JSON.stringify(elasticsearchQuery); + + updateEsQueryForFilterGroup(filterQueryString, indexPattern); + } + return [esFilters]; + } catch (err) { + return [urlFilters, err]; + } +}; diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts deleted file mode 100644 index f2b586b27dba69..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts +++ /dev/null @@ -1,21 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { useEffect, Dispatch } from 'react'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; - -export const useIndexPattern = (setIndexPattern: Dispatch) => { - const core = useKibana(); - useEffect(() => { - const fetch = core.services.http?.fetch; - async function getIndexPattern() { - if (!fetch) throw new Error('Http core services are not defined'); - setIndexPattern(await fetch('/api/uptime/index_pattern', { method: 'GET' })); - } - getIndexPattern(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [core.services.http]); -}; diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/to_static_index_pattern.test.ts.snap b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/to_static_index_pattern.test.ts.snap deleted file mode 100644 index bc02e1054b6f77..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/to_static_index_pattern.test.ts.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`toStaticIndexPattern provides the required fields 1`] = ` -Object { - "attributes": Object { - "fields": "[{\\"name\\":\\"@timestamp\\",\\"type\\":\\"date\\",\\"scripted\\":false,\\"searchable\\":true}]", - }, - "fields": Array [ - Object { - "name": "@timestamp", - "scripted": false, - "searchable": true, - "type": "date", - }, - ], - "id": "foo", - "title": "foo", -} -`; diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/to_static_index_pattern.test.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/to_static_index_pattern.test.ts deleted file mode 100644 index c8015a678c726a..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/to_static_index_pattern.test.ts +++ /dev/null @@ -1,19 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { toStaticIndexPattern } from '../to_static_index_pattern'; - -describe('toStaticIndexPattern', () => { - it('provides the required fields', () => { - const pattern = { - attributes: { - fields: '[{"name":"@timestamp","type":"date","scripted":false,"searchable":true}]', - }, - id: 'foo', - }; - expect(toStaticIndexPattern(pattern)).toMatchSnapshot(); - }); -}); diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts index f3dfbb7d3b5297..45aff24f0449e5 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts @@ -5,6 +5,9 @@ */ export const combineFiltersAndUserSearch = (filters: string, search: string) => { + if (!filters && !search) { + return ''; + } if (!filters) return search; if (!search) return filters; return `(${filters}) and (${search})`; diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts index ced06ce7a1d7b6..ef191ce32e5321 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts @@ -12,5 +12,4 @@ export { getChartDateLabel } from './charts'; export { parameterizeValues } from './parameterize_values'; export { seriesHasDownValues } from './series_has_down_values'; export { stringifyKueries } from './stringify_kueries'; -export { toStaticIndexPattern } from './to_static_index_pattern'; export { UptimeUrlParams, getSupportedUrlParams } from './url_params'; diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts deleted file mode 100644 index b8a12c1e578e39..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export const toStaticIndexPattern = (indexPattern: any) => ({ - ...indexPattern, - fields: JSON.parse(indexPattern.attributes.fields), - title: indexPattern.id, -}); diff --git a/x-pack/legacy/plugins/uptime/public/pages/index.ts b/x-pack/legacy/plugins/uptime/public/pages/index.ts index a96be42eb0deea..17f083ca023ed4 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/index.ts +++ b/x-pack/legacy/plugins/uptime/public/pages/index.ts @@ -5,6 +5,6 @@ */ export { MonitorPage } from './monitor'; -export { OverviewPage } from './overview'; export { NotFoundPage } from './not_found'; export { PageHeader } from './page_header'; +export { OverviewPage } from '../components/connected/'; diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index b9c2284edb0cf6..0f6195c5f4c66e 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -5,30 +5,28 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import React, { Fragment, useContext, useState } from 'react'; +import React, { useContext } from 'react'; import styled from 'styled-components'; import { EmptyState, - FilterGroup, - KueryBar, MonitorList, OverviewPageParsingErrorCallout, StatusPanel, } from '../components/functional'; import { UMUpdateBreadcrumbs } from '../lib/lib'; -import { useIndexPattern, useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks'; +import { useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; import { useTrackPageview } from '../../../infra/public'; -import { combineFiltersAndUserSearch, stringifyKueries, toStaticIndexPattern } from '../lib/helper'; -import { store } from '../state'; -import { setEsKueryString } from '../state/actions'; import { PageHeader } from './page_header'; -import { esKuery, DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; -import { UptimeThemeContext } from '../contexts/uptime_theme_context'; +import { DataPublicPluginStart, IIndexPattern } from '../../../../../../src/plugins/data/public'; +import { UptimeThemeContext } from '../contexts'; +import { FilterGroup, KueryBar } from '../components/connected'; +import { useUpdateKueryString } from '../hooks'; interface OverviewPageProps { autocomplete: DataPublicPluginStart['autocomplete']; setBreadcrumbs: UMUpdateBreadcrumbs; + indexPattern: IIndexPattern; } type Props = OverviewPageProps; @@ -42,72 +40,37 @@ const EuiFlexItemStyled = styled(EuiFlexItem)` } `; -export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { +export const OverviewPageComponent = ({ autocomplete, setBreadcrumbs, indexPattern }: Props) => { const { colors } = useContext(UptimeThemeContext); - const [getUrlParams, updateUrl] = useUrlParams(); + const [getUrlParams] = useUrlParams(); const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams(); const { dateRangeStart, dateRangeEnd, - search, pagination, statusFilter, + search, filters: urlFilters, } = params; - const [indexPattern, setIndexPattern] = useState(undefined); + useUptimeTelemetry(UptimePage.Overview); - useIndexPattern(setIndexPattern); useTrackPageview({ app: 'uptime', path: 'overview' }); useTrackPageview({ app: 'uptime', path: 'overview', delay: 15000 }); - let error: any; - let kueryString: string = ''; - try { - if (urlFilters !== '') { - const filterMap = new Map>(JSON.parse(urlFilters)); - kueryString = stringifyKueries(filterMap); - } - } catch { - kueryString = ''; - } - - const filterQueryString = search || ''; - let filters: any | undefined; - try { - if (filterQueryString || urlFilters) { - if (indexPattern) { - const staticIndexPattern = toStaticIndexPattern(indexPattern); - const combinedFilterString = combineFiltersAndUserSearch(filterQueryString, kueryString); - const ast = esKuery.fromKueryExpression(combinedFilterString); - const elasticsearchQuery = esKuery.toElasticsearchQuery(ast, staticIndexPattern); - filters = JSON.stringify(elasticsearchQuery); - const searchDSL: string = filterQueryString - ? JSON.stringify( - esKuery.toElasticsearchQuery( - esKuery.fromKueryExpression(filterQueryString), - staticIndexPattern - ) - ) - : ''; - store.dispatch(setEsKueryString(searchDSL)); - } - } - } catch (e) { - error = e; - } + const [esFilters, error] = useUpdateKueryString(indexPattern, search, urlFilters); const sharedProps = { dateRangeStart, dateRangeEnd, - filters, statusFilter, + filters: esFilters, }; const linkParameters = stringifyUrlParams(params, true); return ( - + <> @@ -115,15 +78,7 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { - { - if (urlFilters !== filtersKuery) { - updateUrl({ filters: filtersKuery, pagination: '' }); - } - }} - /> + {error && } @@ -133,7 +88,7 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { absoluteDateRangeEnd={absoluteDateRangeEnd} dateRangeStart={dateRangeStart} dateRangeEnd={dateRangeEnd} - filters={filters} + filters={esFilters} statusFilter={statusFilter} /> @@ -141,7 +96,7 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { absoluteStartDate={absoluteDateRangeStart} absoluteEndDate={absoluteDateRangeEnd} dangerColor={colors.danger} - hasActiveFilters={!!filters} + hasActiveFilters={!!esFilters} implementsCustomErrorState={true} linkParameters={linkParameters} successColor={colors.success} @@ -151,6 +106,6 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { }} /> - + ); }; diff --git a/x-pack/legacy/plugins/uptime/public/routes.tsx b/x-pack/legacy/plugins/uptime/public/routes.tsx index 07bba5163922e6..c318a82ab7f199 100644 --- a/x-pack/legacy/plugins/uptime/public/routes.tsx +++ b/x-pack/legacy/plugins/uptime/public/routes.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; -import { MonitorPage, OverviewPage, NotFoundPage } from './pages'; +import { MonitorPage, NotFoundPage, OverviewPage } from './pages'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { UMUpdateBreadcrumbs } from './lib/lib'; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index.ts b/x-pack/legacy/plugins/uptime/public/state/actions/index.ts index 6758006914ab8d..df707584bd844b 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/actions/index.ts @@ -8,4 +8,5 @@ export * from './overview_filters'; export * from './snapshot'; export * from './ui'; export * from './monitor_status'; +export * from './index_patternts'; export * from './ping'; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts b/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts new file mode 100644 index 00000000000000..f52dac805a199e --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createAction } from 'redux-actions'; +import { QueryParams } from './types'; + +export const getIndexPattern = createAction('GET_INDEX_PATTERN'); +export const getIndexPatternSuccess = createAction('GET_INDEX_PATTERN_SUCCESS'); +export const getIndexPatternFail = createAction('GET_INDEX_PATTERN_FAIL'); diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index.ts b/x-pack/legacy/plugins/uptime/public/state/api/index.ts index be79317dc97c2a..2d206388323359 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/api/index.ts @@ -8,4 +8,5 @@ export * from './monitor'; export * from './overview_filters'; export * from './snapshot'; export * from './monitor_status'; +export * from './index_pattern'; export * from './ping'; diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts new file mode 100644 index 00000000000000..2669376d728ab6 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getApiPath } from '../../lib/helper'; + +interface APIParams { + basePath: string; +} + +export const fetchIndexPattern = async ({ basePath }: APIParams) => { + const url = getApiPath(`/api/uptime/index_pattern`, basePath); + + const response = await fetch(url); + if (!response.ok) { + throw new Error(response.statusText); + } + return await response.json(); +}; diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts index 21d4f7a66ad67d..f809454cefb39f 100644 --- a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts @@ -9,6 +9,7 @@ import { fetchMonitorDetailsEffect } from './monitor'; import { fetchOverviewFiltersEffect } from './overview_filters'; import { fetchSnapshotCountEffect } from './snapshot'; import { fetchMonitorStatusEffect } from './monitor_status'; +import { fetchIndexPatternEffect } from './index_pattern'; import { fetchPingHistogramEffect } from './ping'; export function* rootEffect() { @@ -16,5 +17,6 @@ export function* rootEffect() { yield fork(fetchSnapshotCountEffect); yield fork(fetchOverviewFiltersEffect); yield fork(fetchMonitorStatusEffect); + yield fork(fetchIndexPatternEffect); yield fork(fetchPingHistogramEffect); } diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts new file mode 100644 index 00000000000000..a6f9256d5ccd96 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { takeLatest } from 'redux-saga/effects'; +import { getIndexPattern, getIndexPatternSuccess, getIndexPatternFail } from '../actions'; +import { fetchIndexPattern } from '../api'; +import { fetchEffectFactory } from './fetch_effect'; + +export function* fetchIndexPatternEffect() { + yield takeLatest( + getIndexPattern, + fetchEffectFactory(fetchIndexPattern, getIndexPatternSuccess, getIndexPatternFail) + ); +} diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts index c80ada4f63182f..842cb1e9371082 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts @@ -10,6 +10,7 @@ import { overviewFiltersReducer } from './overview_filters'; import { snapshotReducer } from './snapshot'; import { uiReducer } from './ui'; import { monitorStatusReducer } from './monitor_status'; +import { indexPatternReducer } from './index_pattern'; import { pingReducer } from './ping'; export const rootReducer = combineReducers({ @@ -18,5 +19,6 @@ export const rootReducer = combineReducers({ snapshot: snapshotReducer, ui: uiReducer, monitorStatus: monitorStatusReducer, + indexPattern: indexPatternReducer, ping: pingReducer, }); diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts new file mode 100644 index 00000000000000..dff043f81b95c2 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { handleActions, Action } from 'redux-actions'; +import { getIndexPattern, getIndexPatternSuccess, getIndexPatternFail } from '../actions'; + +export interface IndexPatternState { + index_pattern: any; + errors: any[]; + loading: boolean; +} + +const initialState: IndexPatternState = { + index_pattern: null, + loading: false, + errors: [], +}; + +export const indexPatternReducer = handleActions( + { + [String(getIndexPattern)]: state => ({ + ...state, + loading: true, + }), + + [String(getIndexPatternSuccess)]: (state, action: Action) => ({ + ...state, + loading: false, + index_pattern: { ...action.payload }, + }), + + [String(getIndexPatternFail)]: (state, action: Action) => ({ + ...state, + errors: [...state.errors, action.payload], + loading: false, + }), + }, + initialState +); diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts index 5e3bf95d812922..2e27431a5ff14c 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts @@ -45,6 +45,11 @@ describe('state selectors', () => { monitor: null, loading: false, }, + indexPattern: { + index_pattern: null, + loading: false, + errors: [], + }, ping: { pingHistogram: null, loading: false, diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts index 0066241dcc2175..fe6a7a1b7eade5 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts @@ -29,6 +29,10 @@ export const selectMonitorStatus = (state: AppState) => { return state.monitorStatus.status; }; +export const selectIndexPattern = ({ indexPattern }: AppState) => { + return indexPattern.index_pattern; +}; + export const selectPingHistogram = ({ ping, ui }: AppState) => { return { data: ping.pingHistogram, loading: ping.loading, lastRefresh: ui.lastRefresh }; }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index 2f72081a709884..fb2052bb4c87f1 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -8,26 +8,12 @@ import { GraphQLSchema } from 'graphql'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { SavedObjectsLegacyService, - RequestHandler, IRouter, CallAPIOptions, SavedObjectsClientContract, } from 'src/core/server'; -import { ObjectType } from '@kbn/config-schema'; import { UMKibanaRoute } from '../../../rest_api'; -export interface UMFrameworkRouteOptions< - P extends ObjectType, - Q extends ObjectType, - B extends ObjectType -> { - path: string; - method: string; - handler: RequestHandler; - config?: any; - validate: any; -} - type APICaller = ( endpoint: string, clientParams: Record, diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts index f5ff3b8c62ba99..fbef70f106dd80 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts @@ -8,5 +8,5 @@ export * from './framework'; export * from './monitor_states'; export * from './monitors'; export * from './pings'; -export * from './saved_objects'; +export * from './stub_index_pattern'; export * from './telemetry'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/heartbeat_index_pattern.json b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/heartbeat_index_pattern.json deleted file mode 100644 index 444c7510c6a6d2..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/heartbeat_index_pattern.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "attributes": { - "fields": "[{\"name\":\"@timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"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\":\"agent.ephemeral_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.account.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.availability_zone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.image.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.instance.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.instance.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.machine.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.project.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.provider\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.region\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.image.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.image.tag\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.runtime\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ecs.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.action\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.category\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.created\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.dataset\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.duration\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.end\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.kind\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.module\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.outcome\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.risk_score\",\"type\":\"number\",\"esTypes\":[\"float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.risk_score_norm\",\"type\":\"number\",\"esTypes\":[\"float\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.severity\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.start\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.timezone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.ctime\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.device\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.extension\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.gid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.group\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.inode\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mode\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mtime\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.owner\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.uid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.containerized\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.build\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.codename\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.content\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.method\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.referrer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.content\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.status_code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.content.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.response_header.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.total.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.validate.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.validate_body.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.rtt.write_request.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icmp.requests\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icmp.rtt.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.agent.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.agent.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.secured\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.server.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.server.vendor\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.server.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jolokia.url\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.image\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.deployment.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.namespace\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.node.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.pod.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.pod.uid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.replicaset.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.statefulset.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.level\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"monitor.check_group\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"monitor.duration.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"monitor.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"monitor.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"monitor.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"monitor.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.application\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.community_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.direction\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.forwarded_ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.iana_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.protocol\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.transport\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.vendor\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"organization.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.args\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.ppid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.start\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.id\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.title\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resolve.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resolve.rtt.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.ephemeral_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.state\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"socks5.rtt.connect.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"summary.down\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"summary.up\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tags\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tcp.rtt.connect.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tcp.rtt.validate.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timeseries.instance\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.certificate_not_valid_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.certificate_not_valid_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.rtt.handshake.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.fragment\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.password\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.query\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.scheme\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.username\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.device.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", - "timeFieldName": "@timestamp", - "title": "heartbeat-8*" - }, - "id": "heartbeat-8*", - "migrationVersion": { "index-pattern": "6.5.0" }, - "references": [], - "type": "index-pattern", - "updated_at": "2019-08-20T17:45:34.286Z", - "version": "1" -} diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts deleted file mode 100644 index 7628c5bac0660f..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts +++ /dev/null @@ -1,25 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { UMSavedObjectsAdapter } from './types'; -import uptimeIndexPattern from './heartbeat_index_pattern.json'; - -export const savedObjectsAdapter: UMSavedObjectsAdapter = { - getUptimeIndexPattern: async client => { - try { - return await client.get('index-pattern', uptimeIndexPattern.id); - } catch (error) { - return await client.create( - 'index-pattern', - { - ...uptimeIndexPattern.attributes, - title: 'UptimeIndexPattern', - }, - { id: uptimeIndexPattern.id, overwrite: false } - ); - } - }, -}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts deleted file mode 100644 index 0fef1e1428e97b..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { UMSavedObjectsQueryFn } from '../framework'; - -export interface UMSavedObjectsAdapter { - getUptimeIndexPattern: UMSavedObjectsQueryFn; -} diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/index.ts similarity index 67% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts rename to x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/index.ts index bd86daba1bcb62..4ef6e3fa8a6bdf 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { savedObjectsAdapter } from './kibana_saved_objects_adapter'; -export { UMSavedObjectsAdapter } from './types'; +export { StubIndexPatternAdapter, stubIndexPatternAdapter } from './stub_index_pattern'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/stub_index_pattern.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/stub_index_pattern.ts new file mode 100644 index 00000000000000..49ec86af250405 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/stub_index_pattern/stub_index_pattern.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { APICaller } from 'kibana/server'; +import { + IndexPatternsFetcher, + IIndexPattern, +} from '../../../../../../../../src/plugins/data/server'; +import { INDEX_NAMES } from '../../../../common/constants'; +import { UMElasticsearchQueryFn } from '../framework'; + +export interface StubIndexPatternAdapter { + getUptimeIndexPattern: UMElasticsearchQueryFn; +} + +export const stubIndexPatternAdapter: StubIndexPatternAdapter = { + getUptimeIndexPattern: async callES => { + const indexPatternsFetcher = new IndexPatternsFetcher((...rest: Parameters) => + callES(...rest) + ); + + // Since `getDynamicIndexPattern` is called in setup_request (and thus by every endpoint) + // and since `getFieldsForWildcard` will throw if the specified indices don't exist, + // we have to catch errors here to avoid all endpoints returning 500 for users without APM data + // (would be a bad first time experience) + try { + const fields = await indexPatternsFetcher.getFieldsForWildcard({ + pattern: INDEX_NAMES.HEARTBEAT, + }); + + const indexPattern: IIndexPattern = { + fields, + title: INDEX_NAMES.HEARTBEAT, + }; + + return indexPattern; + } catch (e) { + const notExists = e.output?.statusCode === 404; + if (notExists) { + // eslint-disable-next-line no-console + console.error( + `Could not get dynamic index pattern because indices "${INDEX_NAMES.HEARTBEAT}" don't exist` + ); + return; + } + + // re-throw + throw e; + } + }, +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts b/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts index cc11bf90da5f3b..b44a890de3819a 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts @@ -10,7 +10,7 @@ import { elasticsearchPingsAdapter } from '../adapters/pings'; import { licenseCheck } from '../domains'; import { UMDomainLibs, UMServerLibs } from '../lib'; import { elasticsearchMonitorStatesAdapter } from '../adapters/monitor_states'; -import { savedObjectsAdapter } from '../adapters/saved_objects'; +import { stubIndexPatternAdapter } from '../adapters/stub_index_pattern'; import { UptimeCorePlugins, UptimeCoreSetup } from '../adapters/framework'; export function compose(server: UptimeCoreSetup, plugins: UptimeCorePlugins): UMServerLibs { @@ -21,7 +21,7 @@ export function compose(server: UptimeCoreSetup, plugins: UptimeCorePlugins): UM monitors: elasticsearchMonitorsAdapter, monitorStates: elasticsearchMonitorStatesAdapter, pings: elasticsearchPingsAdapter, - savedObjects: savedObjectsAdapter, + stubIndexPattern: stubIndexPatternAdapter, }; return { diff --git a/x-pack/legacy/plugins/uptime/server/lib/lib.ts b/x-pack/legacy/plugins/uptime/server/lib/lib.ts index da87c3ebfe3017..e5ab9940d482d4 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/lib.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/lib.ts @@ -9,7 +9,7 @@ import { UMMonitorsAdapter, UMMonitorStatesAdapter, UMPingsAdapter, - UMSavedObjectsAdapter, + StubIndexPatternAdapter, } from './adapters'; import { UMLicenseCheck } from './domains'; @@ -18,7 +18,7 @@ export interface UMDomainLibs { monitors: UMMonitorsAdapter; monitorStates: UMMonitorStatesAdapter; pings: UMPingsAdapter; - savedObjects: UMSavedObjectsAdapter; + stubIndexPattern: StubIndexPatternAdapter; } export interface UMServerLibs extends UMDomainLibs { diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts index f061307807a42d..cee8eaf3f9caeb 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts @@ -14,11 +14,11 @@ export const createGetIndexPatternRoute: UMRestApiRouteFactory = (libs: UMServer options: { tags: ['access:uptime'], }, - handler: async ({ savedObjectsClient: client }, _context, _request, response): Promise => { + handler: async ({ callES }, _context, _request, response): Promise => { try { return response.ok({ body: { - ...(await libs.savedObjects.getUptimeIndexPattern(client, undefined)), + ...(await libs.stubIndexPattern.getUptimeIndexPattern(callES)), }, }); } catch (e) { From fb334ef56662e56ea0e9b68331914eccc5e96afe Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 30 Jan 2020 08:26:16 -0500 Subject: [PATCH 10/69] [ML] New Platform server shim: update calendar routes to use new platform router (#56264) * migrate calendar routes to NP * add proper types for calendars and events * set actual client in constructor so isLegacy is not stored * remove unnecessary comments * fix calendar schema for missing calendar_id and event_id properties --- ...alendar_manager.js => calendar_manager.ts} | 88 ++++++---- .../{event_manager.js => event_manager.ts} | 39 +++-- .../models/calendar/{index.js => index.ts} | 2 +- .../ml/server/models/job_service/groups.js | 2 +- .../ml/server/models/job_service/jobs.js | 2 +- .../server/new_platform/calendars_schema.ts | 25 +++ .../plugins/ml/server/new_platform/plugin.ts | 2 - .../plugins/ml/server/routes/calendars.js | 110 ------------- .../plugins/ml/server/routes/calendars.ts | 155 ++++++++++++++++++ 9 files changed, 268 insertions(+), 157 deletions(-) rename x-pack/legacy/plugins/ml/server/models/calendar/{calendar_manager.js => calendar_manager.ts} (53%) rename x-pack/legacy/plugins/ml/server/models/calendar/{event_manager.js => event_manager.ts} (51%) rename x-pack/legacy/plugins/ml/server/models/calendar/{index.js => index.ts} (75%) create mode 100644 x-pack/legacy/plugins/ml/server/new_platform/calendars_schema.ts delete mode 100644 x-pack/legacy/plugins/ml/server/routes/calendars.js create mode 100644 x-pack/legacy/plugins/ml/server/routes/calendars.ts diff --git a/x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.js b/x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.ts similarity index 53% rename from x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.js rename to x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.ts index e74a81e92420f6..2487943b5efc07 100644 --- a/x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.js +++ b/x-pack/legacy/plugins/ml/server/models/calendar/calendar_manager.ts @@ -4,23 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ -import _ from 'lodash'; +import { difference } from 'lodash'; import Boom from 'boom'; -import { EventManager } from './event_manager'; +import { EventManager, CalendarEvent } from './event_manager'; + +interface BasicCalendar { + job_ids: string[]; + description?: string; + events: CalendarEvent[]; +} + +export interface Calendar extends BasicCalendar { + calendar_id: string; +} + +export interface FormCalendar extends BasicCalendar { + calendarId: string; +} export class CalendarManager { - constructor(callWithRequest) { - this.callWithRequest = callWithRequest; - this.eventManager = new EventManager(callWithRequest); + private _client: any; + private _eventManager: any; + + constructor(isLegacy: boolean, client: any) { + const actualClient = isLegacy === true ? client : client.ml!.mlClient.callAsCurrentUser; + this._client = actualClient; + this._eventManager = new EventManager(actualClient); } - async getCalendar(calendarId) { + async getCalendar(calendarId: string) { try { - const resp = await this.callWithRequest('ml.calendars', { calendarId }); + const resp = await this._client('ml.calendars', { + calendarId, + }); + const calendars = resp.calendars; if (calendars.length) { const calendar = calendars[0]; - calendar.events = await this.eventManager.getCalendarEvents(calendarId); + calendar.events = await this._eventManager.getCalendarEvents(calendarId); return calendar; } else { throw Boom.notFound(`Calendar with the id "${calendarId}" not found`); @@ -32,9 +53,10 @@ export class CalendarManager { async getAllCalendars() { try { - const calendarsResp = await this.callWithRequest('ml.calendars'); - const events = await this.eventManager.getAllEvents(); - const calendars = calendarsResp.calendars; + const calendarsResp = await this._client('ml.calendars'); + + const events: CalendarEvent[] = await this._eventManager.getAllEvents(); + const calendars: Calendar[] = calendarsResp.calendars; calendars.forEach(cal => (cal.events = [])); // loop events and combine with related calendars @@ -55,24 +77,28 @@ export class CalendarManager { * @param calendarIds * @returns {Promise<*>} */ - async getCalendarsByIds(calendarIds) { + async getCalendarsByIds(calendarIds: string) { try { - const calendars = await this.getAllCalendars(); + const calendars: Calendar[] = await this.getAllCalendars(); return calendars.filter(calendar => calendarIds.includes(calendar.calendar_id)); } catch (error) { throw Boom.badRequest(error); } } - async newCalendar(calendar) { + async newCalendar(calendar: FormCalendar) { const calendarId = calendar.calendarId; const events = calendar.events; delete calendar.calendarId; delete calendar.events; try { - await this.callWithRequest('ml.addCalendar', { calendarId, body: calendar }); + await this._client('ml.addCalendar', { + calendarId, + body: calendar, + }); + if (events.length) { - await this.eventManager.addEvents(calendarId, events); + await this._eventManager.addEvents(calendarId, events); } // return the newly created calendar @@ -82,38 +108,38 @@ export class CalendarManager { } } - async updateCalendar(calendarId, calendar) { - const origCalendar = await this.getCalendar(calendarId); + async updateCalendar(calendarId: string, calendar: Calendar) { + const origCalendar: Calendar = await this.getCalendar(calendarId); try { // update job_ids - const jobsToAdd = _.difference(calendar.job_ids, origCalendar.job_ids); - const jobsToRemove = _.difference(origCalendar.job_ids, calendar.job_ids); + const jobsToAdd = difference(calendar.job_ids, origCalendar.job_ids); + const jobsToRemove = difference(origCalendar.job_ids, calendar.job_ids); // workout the differences between the original events list and the new one // if an event has no event_id, it must be new const eventsToAdd = calendar.events.filter( - event => origCalendar.events.find(e => this.eventManager.isEqual(e, event)) === undefined + event => origCalendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined ); // if an event in the original calendar cannot be found, it must have been deleted - const eventsToRemove = origCalendar.events.filter( - event => calendar.events.find(e => this.eventManager.isEqual(e, event)) === undefined + const eventsToRemove: CalendarEvent[] = origCalendar.events.filter( + event => calendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined ); // note, both of the loops below could be removed if the add and delete endpoints // allowed multiple job_ids - //add all new jobs + // add all new jobs if (jobsToAdd.length) { - await this.callWithRequest('ml.addJobToCalendar', { + await this._client('ml.addJobToCalendar', { calendarId, jobId: jobsToAdd.join(','), }); } - //remove all removed jobs + // remove all removed jobs if (jobsToRemove.length) { - await this.callWithRequest('ml.removeJobFromCalendar', { + await this._client('ml.removeJobFromCalendar', { calendarId, jobId: jobsToRemove.join(','), }); @@ -121,13 +147,13 @@ export class CalendarManager { // add all new events if (eventsToAdd.length !== 0) { - await this.eventManager.addEvents(calendarId, eventsToAdd); + await this._eventManager.addEvents(calendarId, eventsToAdd); } // remove all removed events await Promise.all( eventsToRemove.map(async event => { - await this.eventManager.deleteEvent(calendarId, event.event_id); + await this._eventManager.deleteEvent(calendarId, event.event_id); }) ); } catch (error) { @@ -138,7 +164,7 @@ export class CalendarManager { return await this.getCalendar(calendarId); } - async deleteCalendar(calendarId) { - return this.callWithRequest('ml.deleteCalendar', { calendarId }); + async deleteCalendar(calendarId: string) { + return this._client('ml.deleteCalendar', { calendarId }); } } diff --git a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.js b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts similarity index 51% rename from x-pack/legacy/plugins/ml/server/models/calendar/event_manager.js rename to x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts index 8bdb5dcf4a3e3a..19f2eda4661796 100644 --- a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.js +++ b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts @@ -6,14 +6,24 @@ import Boom from 'boom'; +export interface CalendarEvent { + calendar_id?: string; + event_id?: string; + description: string; + start_time: number; + end_time: number; +} + export class EventManager { - constructor(callWithRequest) { - this.callWithRequest = callWithRequest; + private _client: any; + constructor(client: any) { + this._client = client; } - async getCalendarEvents(calendarId) { + async getCalendarEvents(calendarId: string) { try { - const resp = await this.callWithRequest('ml.events', { calendarId }); + const resp = await this._client('ml.events', { calendarId }); + return resp.events; } catch (error) { throw Boom.badRequest(error); @@ -21,31 +31,38 @@ export class EventManager { } // jobId is optional - async getAllEvents(jobId) { + async getAllEvents(jobId?: string) { const calendarId = '_all'; try { - const resp = await this.callWithRequest('ml.events', { calendarId, jobId }); + const resp = await this._client('ml.events', { + calendarId, + jobId, + }); + return resp.events; } catch (error) { throw Boom.badRequest(error); } } - async addEvents(calendarId, events) { + async addEvents(calendarId: string, events: CalendarEvent[]) { const body = { events }; try { - return await this.callWithRequest('ml.addEvent', { calendarId, body }); + return await this._client('ml.addEvent', { + calendarId, + body, + }); } catch (error) { throw Boom.badRequest(error); } } - async deleteEvent(calendarId, eventId) { - return this.callWithRequest('ml.deleteEvent', { calendarId, eventId }); + async deleteEvent(calendarId: string, eventId: string) { + return this._client('ml.deleteEvent', { calendarId, eventId }); } - isEqual(ev1, ev2) { + isEqual(ev1: CalendarEvent, ev2: CalendarEvent) { return ( ev1.event_id === ev2.event_id && ev1.description === ev2.description && diff --git a/x-pack/legacy/plugins/ml/server/models/calendar/index.js b/x-pack/legacy/plugins/ml/server/models/calendar/index.ts similarity index 75% rename from x-pack/legacy/plugins/ml/server/models/calendar/index.js rename to x-pack/legacy/plugins/ml/server/models/calendar/index.ts index 11f99bc8fd9228..2364c3ac738112 100644 --- a/x-pack/legacy/plugins/ml/server/models/calendar/index.js +++ b/x-pack/legacy/plugins/ml/server/models/calendar/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { CalendarManager } from './calendar_manager'; +export { CalendarManager, Calendar, FormCalendar } from './calendar_manager'; diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js index 91f82f04a9a0c4..58237b2a8a7301 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js +++ b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js @@ -7,7 +7,7 @@ import { CalendarManager } from '../calendar'; export function groupsProvider(callWithRequest) { - const calMngr = new CalendarManager(callWithRequest); + const calMngr = new CalendarManager(true, callWithRequest); async function getAllGroups() { const groups = {}; diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/jobs.js b/x-pack/legacy/plugins/ml/server/models/job_service/jobs.js index b4b476c1f926ea..e60593c9f0ed59 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/jobs.js +++ b/x-pack/legacy/plugins/ml/server/models/job_service/jobs.js @@ -22,7 +22,7 @@ export function jobsProvider(callWithRequest) { const { forceDeleteDatafeed, getDatafeedIdsByJobId } = datafeedsProvider(callWithRequest); const { getAuditMessagesSummary } = jobAuditMessagesProvider(callWithRequest); const { getLatestBucketTimestampByJob } = resultsServiceProvider(callWithRequest); - const calMngr = new CalendarManager(callWithRequest); + const calMngr = new CalendarManager(true, callWithRequest); async function forceDeleteJob(jobId) { return callWithRequest('ml.deleteJob', { jobId, force: true }); diff --git a/x-pack/legacy/plugins/ml/server/new_platform/calendars_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/calendars_schema.ts new file mode 100644 index 00000000000000..f5e59d983a9aa0 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/new_platform/calendars_schema.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; + +export const calendarSchema = { + calendar_id: schema.maybe(schema.string()), + calendarId: schema.string(), + job_ids: schema.arrayOf(schema.maybe(schema.string())), + description: schema.maybe(schema.string()), + events: schema.arrayOf( + schema.maybe( + schema.object({ + event_id: schema.maybe(schema.string()), + calendar_id: schema.maybe(schema.string()), + description: schema.maybe(schema.string()), + start_time: schema.any(), + end_time: schema.any(), + }) + ) + ), +}; diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 681b2ff20c8aa5..2b9219b2226f57 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -41,13 +41,11 @@ import { makeMlUsageCollector } from '../lib/ml_telemetry'; import { notificationRoutes } from '../routes/notification_settings'; // @ts-ignore: could not find declaration file for module import { systemRoutes } from '../routes/system'; -// @ts-ignore: could not find declaration file for module import { dataFrameAnalyticsRoutes } from '../routes/data_frame_analytics'; // @ts-ignore: could not find declaration file for module import { dataRecognizer } from '../routes/modules'; // @ts-ignore: could not find declaration file for module import { dataVisualizerRoutes } from '../routes/data_visualizer'; -// @ts-ignore: could not find declaration file for module import { calendars } from '../routes/calendars'; // @ts-ignore: could not find declaration file for module import { fieldsService } from '../routes/fields_service'; diff --git a/x-pack/legacy/plugins/ml/server/routes/calendars.js b/x-pack/legacy/plugins/ml/server/routes/calendars.js deleted file mode 100644 index 7a0f341ef96665..00000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/calendars.js +++ /dev/null @@ -1,110 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { callWithRequestFactory } from '../client/call_with_request_factory'; -import { wrapError } from '../client/errors'; -import { CalendarManager } from '../models/calendar'; - -function getAllCalendars(callWithRequest) { - const cal = new CalendarManager(callWithRequest); - return cal.getAllCalendars(); -} - -function getCalendar(callWithRequest, calendarId) { - const cal = new CalendarManager(callWithRequest); - return cal.getCalendar(calendarId); -} - -function newCalendar(callWithRequest, calendar) { - const cal = new CalendarManager(callWithRequest); - return cal.newCalendar(calendar); -} - -function updateCalendar(callWithRequest, calendarId, calendar) { - const cal = new CalendarManager(callWithRequest); - return cal.updateCalendar(calendarId, calendar); -} - -function deleteCalendar(callWithRequest, calendarId) { - const cal = new CalendarManager(callWithRequest); - return cal.deleteCalendar(calendarId); -} - -function getCalendarsByIds(callWithRequest, calendarIds) { - const cal = new CalendarManager(callWithRequest); - return cal.getCalendarsByIds(calendarIds); -} - -export function calendars({ commonRouteConfig, elasticsearchPlugin, route }) { - route({ - method: 'GET', - path: '/api/ml/calendars', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return getAllCalendars(callWithRequest).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/calendars/{calendarIds}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const calendarIds = request.params.calendarIds.split(','); - if (calendarIds.length === 1) { - return getCalendar(callWithRequest, calendarIds[0]).catch(resp => wrapError(resp)); - } else { - return getCalendarsByIds(callWithRequest, calendarIds).catch(resp => wrapError(resp)); - } - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'PUT', - path: '/api/ml/calendars', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const body = request.payload; - return newCalendar(callWithRequest, body).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'PUT', - path: '/api/ml/calendars/{calendarId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const calendarId = request.params.calendarId; - const body = request.payload; - return updateCalendar(callWithRequest, calendarId, body).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'DELETE', - path: '/api/ml/calendars/{calendarId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const calendarId = request.params.calendarId; - return deleteCalendar(callWithRequest, calendarId).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); -} diff --git a/x-pack/legacy/plugins/ml/server/routes/calendars.ts b/x-pack/legacy/plugins/ml/server/routes/calendars.ts new file mode 100644 index 00000000000000..19d614a4e6a228 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/calendars.ts @@ -0,0 +1,155 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandlerContext } from 'src/core/server'; +import { schema } from '@kbn/config-schema'; +import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { wrapError } from '../client/error_wrapper'; +import { RouteInitialization } from '../new_platform/plugin'; +import { calendarSchema } from '../new_platform/calendars_schema'; +import { CalendarManager, Calendar, FormCalendar } from '../models/calendar'; + +function getAllCalendars(context: RequestHandlerContext) { + const cal = new CalendarManager(false, context); + return cal.getAllCalendars(); +} + +function getCalendar(context: RequestHandlerContext, calendarId: string) { + const cal = new CalendarManager(false, context); + return cal.getCalendar(calendarId); +} + +function newCalendar(context: RequestHandlerContext, calendar: FormCalendar) { + const cal = new CalendarManager(false, context); + return cal.newCalendar(calendar); +} + +function updateCalendar(context: RequestHandlerContext, calendarId: string, calendar: Calendar) { + const cal = new CalendarManager(false, context); + return cal.updateCalendar(calendarId, calendar); +} + +function deleteCalendar(context: RequestHandlerContext, calendarId: string) { + const cal = new CalendarManager(false, context); + return cal.deleteCalendar(calendarId); +} + +function getCalendarsByIds(context: RequestHandlerContext, calendarIds: string) { + const cal = new CalendarManager(false, context); + return cal.getCalendarsByIds(calendarIds); +} + +export function calendars({ xpackMainPlugin, router }: RouteInitialization) { + router.get( + { + path: '/api/ml/calendars', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const resp = await getAllCalendars(context); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + router.get( + { + path: '/api/ml/calendars/{calendarIds}', + validate: { + params: schema.object({ calendarIds: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + let returnValue; + try { + const calendarIds = request.params.calendarIds.split(','); + + if (calendarIds.length === 1) { + returnValue = await getCalendar(context, calendarIds[0]); + } else { + returnValue = await getCalendarsByIds(context, calendarIds); + } + + return response.ok({ + body: returnValue, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + router.put( + { + path: '/api/ml/calendars', + validate: { + body: schema.object({ ...calendarSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const body = request.body; + const resp = await newCalendar(context, body); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + router.put( + { + path: '/api/ml/calendars/{calendarId}', + validate: { + params: schema.object({ calendarId: schema.string() }), + body: schema.object({ ...calendarSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { calendarId } = request.params; + const body = request.body; + const resp = await updateCalendar(context, calendarId, body); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + router.delete( + { + path: '/api/ml/calendars/{calendarId}', + validate: { + params: schema.object({ calendarId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { calendarId } = request.params; + const resp = await deleteCalendar(context, calendarId); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); +} From 371abf6fd22a0d1fcd008ad56522fb97b0b73ae8 Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Thu, 30 Jan 2020 14:01:01 +0000 Subject: [PATCH 11/69] [Filter Bar] Remove flickering when opening filter bar popover (#56222) Co-authored-by: Elastic Machine --- src/plugins/data/public/ui/filter_bar/filter_bar.tsx | 1 + src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx index 2f1b1f8588eb92..2aaceddd68f0ce 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx @@ -96,6 +96,7 @@ function FilterBarUI(props: Props) { withTitle panelPaddingSize="none" ownFocus={true} + initialFocus=".filterEditor__hiddenItem" >

    diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx index b058d231b83065..b83c3a8e905dcb 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx @@ -95,6 +95,7 @@ class FilterEditorUI extends Component { defaultMessage="Edit filter" /> + {this.state.isCustomEditorOpen ? ( From 2d3a656b7570ce47003c81ca3efd7bbf7bd23690 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 30 Jan 2020 15:57:10 +0100 Subject: [PATCH 12/69] Sort returned list of objects (#56356) --- .../application/hooks/use_data_init/use_data_init.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts index 2212827c1f5980..2722c7a1665d3d 100644 --- a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts +++ b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts @@ -51,8 +51,12 @@ export const useDataInit = () => { }); dispatch({ type: 'setCurrentTextObject', payload: newObject }); } else { - // For now, we always take the first text object returned. - dispatch({ type: 'setCurrentTextObject', payload: results[0] }); + dispatch({ + type: 'setCurrentTextObject', + // For backwards compatibility, we sort here according to date created to + // always take the first item created. + payload: results.sort((a, b) => a.createdAt - b.createdAt)[0], + }); } } catch (e) { setError(e); From 6bc9cde843dd6099c3881c87ddcdc520d7393dc2 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 30 Jan 2020 16:00:42 +0100 Subject: [PATCH 13/69] Fix off by one issue for getting endpoint for opening docs and tracking (#56364) Fix security docs --- .../public/lib/autocomplete/get_endpoint_from_position.ts | 5 ++++- .../server/spec/generated/security.put_privileges.json | 2 +- .../server/spec/overrides/security.delete_privileges.json | 2 ++ .../server/spec/overrides/security.put_privileges.json | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts b/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts index cb037e29e33f64..8cac8d1208cee9 100644 --- a/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts +++ b/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts @@ -30,7 +30,10 @@ export function getEndpointFromPosition(editor: CoreEditor, pos: Position, parse const context = { ...getCurrentMethodAndTokenPaths( editor, - { column: lineValue.length, lineNumber: pos.lineNumber }, + { + column: lineValue.length + 1 /* Go to the very end of the line */, + lineNumber: pos.lineNumber, + }, parser, true ), diff --git a/x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json b/x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json index 7ecffc780c0662..a42d5eb6c953ee 100644 --- a/x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json +++ b/x-pack/plugins/console_extensions/server/spec/generated/security.put_privileges.json @@ -12,7 +12,7 @@ "POST" ], "patterns": [ - "_security/privilege/" + "_security/privilege" ], "documentation": "TODO" } diff --git a/x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json index 35fb78c532c12b..5486098ff7bd8e 100644 --- a/x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json +++ b/x-pack/plugins/console_extensions/server/spec/overrides/security.delete_privileges.json @@ -1,3 +1,5 @@ { + "security.delete_privileges": { "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html" + } } diff --git a/x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json index ae37d9a889543d..9ebb1046047a73 100644 --- a/x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json +++ b/x-pack/plugins/console_extensions/server/spec/overrides/security.put_privileges.json @@ -1,3 +1,5 @@ { + "security.put_privileges": { "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-privileges.html" + } } From ed9cf94920bd1ed0e3d368c711a8dd3089f40b34 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 30 Jan 2020 16:31:27 +0100 Subject: [PATCH 14/69] [Watcher] Follow up on flaky functional test (#56384) * Skip flaky watcher FF test * Give a bit more time for machines on CI * Update watcher_test.js * Revert "Update watcher_test.js" This reverts commit 8a0289f9f15d92bdfd70ec2eb4dbc2b4c9dcf903. * Revert "Give a bit more time for machines on CI" This reverts commit d11228d6187121cf1cca2415a5c6f77de887f7bc. --- x-pack/test/functional/apps/watcher/watcher_test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/watcher/watcher_test.js b/x-pack/test/functional/apps/watcher/watcher_test.js index a3b955f8fccee3..a2da0aad2d3c56 100644 --- a/x-pack/test/functional/apps/watcher/watcher_test.js +++ b/x-pack/test/functional/apps/watcher/watcher_test.js @@ -18,7 +18,10 @@ export default function({ getService, getPageObjects }) { const esSupertest = getService('esSupertest'); const PageObjects = getPageObjects(['security', 'common', 'header', 'settings', 'watcher']); - describe('watcher_test', function() { + // Still flaky test :c + // https://github.com/elastic/kibana/pull/56361 + // https://github.com/elastic/kibana/pull/56304 + describe.skip('watcher_test', function() { before('initialize tests', async () => { // There may be system watches if monitoring was previously enabled // These cannot be deleted via the UI, so we need to delete via the API From c504c40ba911950be770c164fe82f669f03a9633 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 30 Jan 2020 16:42:03 +0100 Subject: [PATCH 15/69] exclude tutorial resources from code ownership (#55987) Co-authored-by: Elastic Machine --- .github/CODEOWNERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 37ca1ff7bbdec6..2e2b20a46baede 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,7 +12,6 @@ /src/legacy/core_plugins/kibana/public/discover/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/visualize/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/local_application_service/ @elastic/kibana-app -/src/legacy/core_plugins/kibana/public/home/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/dev_tools/ @elastic/kibana-app /src/legacy/core_plugins/metrics/ @elastic/kibana-app /src/legacy/core_plugins/vis_type_vislib/ @elastic/kibana-app @@ -20,6 +19,10 @@ /src/plugins/home/public @elastic/kibana-app /src/plugins/home/server/*.ts @elastic/kibana-app /src/plugins/home/server/services/ @elastic/kibana-app +# Exclude tutorial resources folder for now because they are not owned by Kibana app and most will move out soon +/src/legacy/core_plugins/kibana/public/home/*.ts @elastic/kibana-app +/src/legacy/core_plugins/kibana/public/home/*.scss @elastic/kibana-app +/src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-app /src/plugins/kibana_legacy/ @elastic/kibana-app /src/plugins/timelion/ @elastic/kibana-app /src/plugins/dev_tools/ @elastic/kibana-app From 74b9ed6414d8801d4ac3cd9b62715f9f7c742ec8 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 30 Jan 2020 16:42:56 +0100 Subject: [PATCH 16/69] Move tsvb server to new platform (#55310) --- .i18nrc.json | 2 +- .../core_plugins/vis_type_timeseries/index.ts | 6 -- .../public/components/aggs/filter_ratio.js | 2 +- .../public/components/aggs/metric_select.js | 8 +- .../public/components/aggs/moving_average.js | 2 +- .../public/components/aggs/std_agg.js | 2 +- .../public/components/aggs/top_hit.js | 2 +- .../public/components/index_pattern.js | 11 ++- .../components/lib/convert_series_to_vars.js | 2 +- .../public/components/lib/get_interval.js | 2 +- .../components/lib/series_change_handler.js | 2 +- .../public/components/splits/terms.js | 2 +- .../public/components/vis_editor.js | 2 +- .../components/vis_editor_visualization.js | 2 +- .../public/components/vis_picker.js | 2 +- .../public/components/vis_types/gauge/vis.js | 2 +- .../components/vis_types/markdown/vis.js | 2 +- .../public/components/vis_types/metric/vis.js | 4 +- .../components/vis_types/table/is_sortable.js | 2 +- .../public/components/vis_types/table/vis.js | 4 +- .../components/vis_types/timeseries/series.js | 2 +- .../components/vis_types/timeseries/vis.js | 2 +- .../public/components/vis_types/top_n/vis.js | 4 +- .../public/components/vis_with_splits.js | 2 +- .../public/lib/check_ui_restrictions.js | 5 +- .../public/lib/fetch_fields.js | 2 +- .../{common => public/lib}/set_is_reversed.js | 6 +- .../public/lib/validate_interval.js | 2 +- .../public/metrics_type.ts | 2 +- .../public/visualizations/views/gauge.js | 4 +- .../public/visualizations/views/metric.js | 2 +- .../public/visualizations/views/top_n.js | 2 +- .../vis_type_timeseries/server/init.ts | 44 --------- .../server/lib/get_fields.js | 37 -------- .../server/lib/get_index_pattern_service.js | 30 ------- .../server/lib/search_strategies/index.js | 20 ----- .../strategies/abstract_search_strategy.js | 42 --------- .../__snapshots__/model_options.test.js.snap | 0 .../vis_type_timeseries/common/agg_lookup.js | 0 .../common/agg_lookup.test.js | 0 .../vis_type_timeseries/common/basic_aggs.js | 0 .../common/calculate_label.js | 0 .../common/calculate_label.test.js | 0 .../common/extract_index_patterns.js | 0 .../common/extract_index_patterns.test.js | 0 .../vis_type_timeseries/common/field_types.js | 0 .../common/get_last_value.js | 0 .../common/get_last_value.test.js | 0 .../common/interval_regexp.js | 0 .../common/interval_regexp.test.js | 0 .../common/metric_types.js | 0 .../common/model_options.js | 0 .../common/model_options.test.js | 0 .../vis_type_timeseries/common/panel_types.js | 0 .../common/timerange_data_modes.js | 0 .../common/to_percentile_number.js | 0 .../common/ui_restrictions.js | 0 .../vis_type_timeseries/server/index.ts | 7 ++ .../server/lib/get_fields.ts | 89 +++++++++++++++++++ .../server/lib/get_vis_data.ts | 16 ++-- .../default_search_capabilities.js | 0 .../default_search_capabilities.test.js | 0 .../server/lib/search_strategies}/index.ts | 3 +- .../search_requests}/abstract_request.js | 0 .../search_requests}/abstract_request.test.js | 0 .../search_requests}/multi_search_request.js | 0 .../multi_search_request.test.js | 0 .../search_requests}/search_request.js | 0 .../search_requests}/search_request.test.js | 0 .../search_requests}/single_search_request.js | 0 .../single_search_request.test.js | 0 .../search_strategies_registry.test.ts} | 52 ++++------- .../search_strategy_registry.ts} | 40 ++++----- .../abstract_search_strategy.test.js | 0 .../strategies/abstract_search_strategy.ts | 87 ++++++++++++++++++ .../strategies/default_search_strategy.js | 2 +- .../default_search_strategy.test.js | 0 .../annotations}/build_request_body.js | 0 .../annotations}/get_request_params.js | 0 .../vis_data/build_processor_function.test.ts | 0 .../lib/vis_data/build_processor_function.ts | 0 .../server/lib/vis_data/get_annotations.js | 4 +- .../vis_data/get_interval_and_timefield.js | 0 .../get_interval_and_timefield.test.js | 0 .../server/lib/vis_data/get_panel_data.d.ts | 0 .../server/lib/vis_data/get_panel_data.js | 0 .../server/lib/vis_data/get_series_data.js | 9 +- .../server/lib/vis_data/get_table_data.js | 10 +-- .../lib/vis_data/handle_error_response.js | 0 .../bucket_transform.test.js.snap | 0 .../lib/vis_data/helpers/bucket_transform.js | 0 .../vis_data/helpers/bucket_transform.test.js | 0 .../lib/vis_data/helpers/calculate_auto.js | 0 .../server/lib/vis_data/helpers/format_key.js | 0 .../lib/vis_data/helpers/get_active_series.js | 0 .../lib/vis_data/helpers/get_agg_value.js | 0 .../vis_data/helpers/get_agg_value.test.js | 0 .../lib/vis_data/helpers/get_bucket_size.js | 2 +- .../vis_data/helpers/get_bucket_size.test.js | 0 .../lib/vis_data/helpers/get_buckets_path.js | 0 .../vis_data/helpers/get_buckets_path.test.js | 0 .../helpers/get_default_decoration.js | 0 .../helpers/get_default_decoration.test.js | 0 .../helpers/get_es_query_uisettings.js | 0 .../vis_data/helpers/get_es_shard_timeout.js | 0 .../helpers/get_es_shard_timeout.test.js | 0 .../lib/vis_data/helpers/get_index_pattern.js | 0 .../lib/vis_data/helpers/get_last_metric.js | 0 .../vis_data/helpers/get_last_metric.test.js | 0 .../vis_data/helpers/get_sibling_agg_value.js | 0 .../helpers/get_sibling_agg_value.test.js | 0 .../lib/vis_data/helpers/get_split_colors.js | 0 .../server/lib/vis_data/helpers/get_splits.js | 0 .../lib/vis_data/helpers/get_splits.test.js | 0 .../lib/vis_data/helpers/get_timerange.js | 0 .../vis_data/helpers/get_timerange.test.js | 0 .../vis_data/helpers/get_timerange_mode.js | 0 .../server/lib/vis_data/helpers/index.js | 0 .../server/lib/vis_data/helpers/map_bucket.js | 0 .../lib/vis_data/helpers/map_bucket.test.js | 0 .../lib/vis_data/helpers/moving_fn_scripts.js | 0 .../helpers/moving_fn_scripts.test.js | 0 .../lib/vis_data/helpers/parse_interval.js | 0 .../lib/vis_data/helpers/parse_settings.js | 0 .../vis_data/helpers/parse_settings.test.js | 0 .../server/lib/vis_data/helpers/timestamp.js | 0 .../lib/vis_data/helpers/timestamp.test.js | 0 .../lib/vis_data/helpers/unit_to_seconds.js | 0 .../vis_data/helpers/unit_to_seconds.test.js | 0 .../server/lib/vis_data/offset_time.js | 0 .../server/lib/vis_data/offset_time.test.js | 0 .../annotations/date_histogram.js | 2 +- .../request_processors/annotations/index.js | 0 .../request_processors/annotations/query.js | 2 +- .../annotations/top_hits.js | 0 .../series/date_histogram.js | 2 +- .../series/date_histogram.test.js | 0 .../series/filter_ratios.js | 0 .../series/filter_ratios.test.js | 0 .../request_processors/series/index.js | 0 .../series/metric_buckets.js | 0 .../series/metric_buckets.test.js | 0 .../series/normalize_query.js | 0 .../series/normalize_query.test.js | 0 .../request_processors/series/query.js | 2 +- .../request_processors/series/query.test.js | 0 .../series/sibling_buckets.js | 0 .../series/sibling_buckets.test.js | 0 .../series/split_by_everything.js | 0 .../series/split_by_everything.test.js | 0 .../series/split_by_filter.js | 2 +- .../series/split_by_filter.test.js | 0 .../series/split_by_filters.js | 2 +- .../series/split_by_filters.test.js | 0 .../series/split_by_terms.js | 0 .../series/split_by_terms.test.js | 0 .../table/calculate_agg_root.js | 0 .../table/date_histogram.js | 2 +- .../request_processors/table/filter_ratios.js | 0 .../request_processors/table/index.js | 0 .../table/metric_buckets.js | 0 .../table/normalize_query.js | 0 .../table/normalize_query.test.js | 0 .../request_processors/table/pivot.js | 0 .../request_processors/table/query.js | 2 +- .../table/sibling_buckets.js | 0 .../table/split_by_everything.js | 2 +- .../table/split_by_terms.js | 2 +- .../annotations/buckets.js | 0 .../response_processors/annotations/filter.js | 0 .../annotations/filter.test.js | 0 .../response_processors/annotations/index.js | 0 .../response_processors/series/_series_agg.js | 0 .../series/_series_agg.test.js | 0 .../series/drop_last_bucket.js | 0 .../response_processors/series/index.js | 0 .../response_processors/series/math.js | 0 .../response_processors/series/percentile.js | 0 .../series/percentile.test.js | 0 .../series/percentile_rank.js | 0 .../response_processors/series/series_agg.js | 0 .../series/series_agg.test.js | 0 .../series/std_deviation_bands.js | 0 .../series/std_deviation_bands.test.js | 0 .../series/std_deviation_sibling.js | 0 .../series/std_deviation_sibling.test.js | 0 .../response_processors/series/std_metric.js | 0 .../series/std_metric.test.js | 0 .../response_processors/series/std_sibling.js | 0 .../series/std_sibling.test.js | 0 .../response_processors/series/time_shift.js | 0 .../series/time_shift.test.js | 0 .../response_processors/table/_series_agg.js | 0 .../table/drop_last_bucket.js | 0 .../response_processors/table/index.js | 0 .../response_processors/table/math.js | 0 .../response_processors/table/percentile.js | 0 .../table/percentile_rank.js | 0 .../response_processors/table/series_agg.js | 0 .../response_processors/table/std_metric.js | 0 .../response_processors/table/std_sibling.js | 0 .../series/build_request_body.test.ts | 0 .../lib/vis_data/series/build_request_body.ts | 2 +- .../lib/vis_data/series/get_request_params.js | 0 .../vis_data/series/handle_response_body.js | 0 .../lib/vis_data/table/build_request_body.js | 0 .../lib/vis_data/table/process_bucket.js | 0 .../vis_type_timeseries/server/plugin.ts | 60 +++++++------ .../server/routes/fields.ts} | 37 +++++--- .../server/routes/post_vis_schema.ts | 0 .../vis_type_timeseries/server/routes/vis.ts | 15 ++-- .../framework/kibana_framework_adapter.ts | 3 +- .../metrics/kibana_metrics_adapter.ts | 7 +- .../lib/populate_series_with_tsvb_data.ts | 8 +- x-pack/legacy/plugins/rollup/index.js | 2 +- .../call_with_request_factory.js | 8 +- .../register_rollup_search_strategy.js | 18 ++-- .../register_rollup_search_strategy.test.js | 18 ++-- 218 files changed, 405 insertions(+), 385 deletions(-) rename src/legacy/core_plugins/vis_type_timeseries/{common => public/lib}/set_is_reversed.js (92%) delete mode 100644 src/legacy/core_plugins/vis_type_timeseries/server/init.ts delete mode 100644 src/legacy/core_plugins/vis_type_timeseries/server/lib/get_fields.js delete mode 100644 src/legacy/core_plugins/vis_type_timeseries/server/lib/get_index_pattern_service.js delete mode 100644 src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/index.js delete mode 100644 src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.js rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/__snapshots__/model_options.test.js.snap (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/agg_lookup.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/agg_lookup.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/basic_aggs.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/calculate_label.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/calculate_label.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/extract_index_patterns.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/extract_index_patterns.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/field_types.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/get_last_value.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/get_last_value.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/interval_regexp.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/interval_regexp.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/metric_types.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/model_options.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/model_options.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/panel_types.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/timerange_data_modes.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/to_percentile_number.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/common/ui_restrictions.js (100%) create mode 100644 src/plugins/vis_type_timeseries/server/lib/get_fields.ts rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/get_vis_data.ts (87%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server => plugins/vis_type_timeseries/server/lib/search_strategies}/index.ts (87%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/abstract_request.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/abstract_request.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/multi_search_request.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/multi_search_request.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/search_request.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/search_request.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/single_search_request.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests => plugins/vis_type_timeseries/server/lib/search_strategies/search_requests}/single_search_request.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.test.js => plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts} (61%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.js => plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts} (57%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.js (100%) create mode 100644 src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js (95%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations => plugins/vis_type_timeseries/server/lib/vis_data/annotations}/build_request_body.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations => plugins/vis_type_timeseries/server/lib/vis_data/annotations}/get_request_params.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_annotations.js (96%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_panel_data.d.ts (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_panel_data.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_series_data.js (91%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/get_table_data.js (90%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/handle_error_response.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/calculate_auto.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/format_key.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js (97%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_index_pattern.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/offset_time.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/offset_time.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js (94%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js (97%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js (96%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js (96%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js (94%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js (94%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js (96%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js (96%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js (95%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js (95%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts (95%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/series/get_request_params.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/table/build_request_body.js (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/lib/vis_data/table/process_bucket.js (100%) rename src/{legacy/core_plugins/vis_type_timeseries/server/routes/fields.js => plugins/vis_type_timeseries/server/routes/fields.ts} (54%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/routes/post_vis_schema.ts (100%) rename src/{legacy/core_plugins => plugins}/vis_type_timeseries/server/routes/vis.ts (85%) diff --git a/.i18nrc.json b/.i18nrc.json index 98c36b43e5d8fa..1230151212f573 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -40,7 +40,7 @@ "visTypeMetric": "src/legacy/core_plugins/vis_type_metric", "visTypeTable": "src/legacy/core_plugins/vis_type_table", "visTypeTagCloud": "src/legacy/core_plugins/vis_type_tagcloud", - "visTypeTimeseries": "src/legacy/core_plugins/vis_type_timeseries", + "visTypeTimeseries": ["src/legacy/core_plugins/vis_type_timeseries", "src/plugins/vis_type_timeseries"], "visTypeVega": "src/legacy/core_plugins/vis_type_vega", "visTypeVislib": "src/legacy/core_plugins/vis_type_vislib", "visualizations": [ diff --git a/src/legacy/core_plugins/vis_type_timeseries/index.ts b/src/legacy/core_plugins/vis_type_timeseries/index.ts index a502bb174bc997..3ad8ba3a31c17e 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/index.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/index.ts @@ -21,7 +21,6 @@ import { resolve } from 'path'; import { Legacy } from 'kibana'; import { LegacyPluginApi, LegacyPluginInitializer } from '../../../../src/legacy/types'; -import { VisTypeTimeseriesSetup } from '../../../plugins/vis_type_timeseries/server'; const metricsPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) => new Plugin({ @@ -47,11 +46,6 @@ const metricsPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPlu }, }, }, - init: (server: Legacy.Server) => { - const visTypeTimeSeriesPlugin = server.newPlatform.setup.plugins - .metrics as VisTypeTimeseriesSetup; - visTypeTimeSeriesPlugin.__legacy.registerLegacyAPI({ server }); - }, config(Joi: any) { return Joi.object({ enabled: Joi.boolean().default(true), diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/filter_ratio.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/filter_ratio.js index 355c4723587d6f..5bd7f6557e8877 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/filter_ratio.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/filter_ratio.js @@ -36,7 +36,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; -import { METRIC_TYPES } from '../../../common/metric_types'; +import { METRIC_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/metric_types'; export const FilterRatioAgg = props => { const { series, fields, panel } = props; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/metric_select.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/metric_select.js index 5e2f148ab5a6e5..18daecd6999037 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/metric_select.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/metric_select.js @@ -23,10 +23,10 @@ import { includes } from 'lodash'; import { injectI18n } from '@kbn/i18n/react'; import { EuiComboBox } from '@elastic/eui'; import { calculateSiblings } from '../lib/calculate_siblings'; -import { calculateLabel } from '../../../common/calculate_label'; -import { basicAggs } from '../../../common/basic_aggs'; -import { toPercentileNumber } from '../../../common/to_percentile_number'; -import { METRIC_TYPES } from '../../../common/metric_types'; +import { calculateLabel } from '../../../../../../plugins/vis_type_timeseries/common/calculate_label'; +import { basicAggs } from '../../../../../../plugins/vis_type_timeseries/common/basic_aggs'; +import { toPercentileNumber } from '../../../../../../plugins/vis_type_timeseries/common/to_percentile_number'; +import { METRIC_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/metric_types'; function createTypeFilter(restrict, exclude) { return metric => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/moving_average.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/moving_average.js index 3b9d0ab2826826..5843eab3f4707a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/moving_average.js @@ -36,7 +36,7 @@ import { EuiFieldNumber, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { MODEL_TYPES } from '../../../common/model_options'; +import { MODEL_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/model_options'; const DEFAULTS = { model_type: MODEL_TYPES.UNWEIGHTED, diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/std_agg.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/std_agg.js index 67fe9403e402b9..61e5c60cbd72aa 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/std_agg.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/std_agg.js @@ -34,7 +34,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; -import { METRIC_TYPES } from '../../../common/metric_types'; +import { METRIC_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/metric_types'; export function StandardAgg(props) { const { model, panel, series, fields, uiRestrictions } = props; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/top_hit.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/top_hit.js index fa92713046aca8..df13b943940610 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/top_hit.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/aggs/top_hit.js @@ -36,7 +36,7 @@ import { } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; -import { PANEL_TYPES } from '../../../common/panel_types'; +import { PANEL_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/panel_types'; const isFieldTypeEnabled = (fieldRestrictions, fieldType) => fieldRestrictions.length ? fieldRestrictions.includes(fieldType) : true; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js index 352747013fe29e..de8469adfb8a73 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js @@ -42,8 +42,11 @@ import { AUTO_INTERVAL, } from './lib/get_interval'; import { i18n } from '@kbn/i18n'; -import { TIME_RANGE_DATA_MODES, TIME_RANGE_MODE_KEY } from '../../common/timerange_data_modes'; -import { PANEL_TYPES } from '../../common/panel_types'; +import { + TIME_RANGE_DATA_MODES, + TIME_RANGE_MODE_KEY, +} from '../../../../../plugins/vis_type_timeseries/common/timerange_data_modes'; +import { PANEL_TYPES } from '../../../../../plugins/vis_type_timeseries/common/panel_types'; import { isTimerangeModeEnabled } from '../lib/check_ui_restrictions'; import { VisDataContext } from '../contexts/vis_data_context'; @@ -138,8 +141,8 @@ export const IndexPattern = ({ fields, prefix, onChange, disabled, model: _model {i18n.translate('visTypeTimeseries.indexPattern.timeRange.hint', { - defaultMessage: `This setting controls the timespan used for matching documents. - "Entire timerange" will match all the documents selected in the timepicker. + defaultMessage: `This setting controls the timespan used for matching documents. + "Entire timerange" will match all the documents selected in the timepicker. "Last value" will match only the documents for the specified interval from the end of the timerange.`, })} diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/convert_series_to_vars.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/convert_series_to_vars.js index bcab9ec026d9ae..73fc8dac2b5645 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/convert_series_to_vars.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/convert_series_to_vars.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { getLastValue } from '../../../common/get_last_value'; +import { getLastValue } from '../../../../../../plugins/vis_type_timeseries/common/get_last_value'; import { createTickFormatter } from './tick_formatter'; import moment from 'moment'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js index 05d00f6bede1af..a6aefe067dd62b 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js @@ -20,7 +20,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import { parseEsInterval } from '../../../../data/public'; -import { GTE_INTERVAL_RE } from '../../../common/interval_regexp'; +import { GTE_INTERVAL_RE } from '../../../../../../plugins/vis_type_timeseries/common/interval_regexp'; export const AUTO_INTERVAL = 'auto'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/series_change_handler.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/series_change_handler.js index b13f89c204292c..e773782969d161 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/series_change_handler.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/series_change_handler.js @@ -19,7 +19,7 @@ import _ from 'lodash'; import { newMetricAggFn } from './new_metric_agg_fn'; -import { isBasicAgg } from '../../../common/agg_lookup'; +import { isBasicAgg } from '../../../../../../plugins/vis_type_timeseries/common/agg_lookup'; import { handleAdd, handleChange } from './collection_actions'; export const seriesChangeHandler = (props, items) => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/splits/terms.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/splits/terms.js index 111da86d71ecb3..0fddc4f8c1d87d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/splits/terms.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/splits/terms.js @@ -36,7 +36,7 @@ import { EuiFieldText, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import { FIELD_TYPES } from '../../../common/field_types'; +import { FIELD_TYPES } from '../../../../../../plugins/vis_type_timeseries/common/field_types'; import { STACKED_OPTIONS } from '../../visualizations/constants'; const DEFAULTS = { terms_direction: 'desc', terms_size: 10, terms_order_by: '_count' }; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index ae39d75c7a2d1d..3dedb67bd1d99a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -28,7 +28,7 @@ import { VisPicker } from './vis_picker'; import { PanelConfig } from './panel_config'; import { createBrushHandler } from '../lib/create_brush_handler'; import { fetchFields } from '../lib/fetch_fields'; -import { extractIndexPatterns } from '../../common/extract_index_patterns'; +import { extractIndexPatterns } from '../../../../../plugins/vis_type_timeseries/common/extract_index_patterns'; import { esKuery } from '../../../../../plugins/data/public'; import { npStart } from 'ui/new_platform'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js index a376905495c521..c45a4d68e8aada 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js @@ -28,7 +28,7 @@ import { isGteInterval, AUTO_INTERVAL, } from './lib/get_interval'; -import { PANEL_TYPES } from '../../common/panel_types'; +import { PANEL_TYPES } from '../../../../../plugins/vis_type_timeseries/common/panel_types'; import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy'; const MIN_CHART_HEIGHT = 300; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_picker.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_picker.js index 8d2673ea24cb2c..2c4a11f8880ffa 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_picker.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_picker.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { EuiTabs, EuiTab } from '@elastic/eui'; import { injectI18n } from '@kbn/i18n/react'; -import { PANEL_TYPES } from '../../common/panel_types'; +import { PANEL_TYPES } from '../../../../../plugins/vis_type_timeseries/common/panel_types'; function VisPickerItem(props) { const { label, type, selected } = props; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/gauge/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/gauge/vis.js index 5d6bb55f33db69..7d30a1f0c8df54 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/gauge/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/gauge/vis.js @@ -23,7 +23,7 @@ import { visWithSplits } from '../../vis_with_splits'; import { createTickFormatter } from '../../lib/tick_formatter'; import _, { get, isUndefined, assign, includes } from 'lodash'; import { Gauge } from '../../../visualizations/views/gauge'; -import { getLastValue } from '../../../../common/get_last_value'; +import { getLastValue } from '../../../../../../../plugins/vis_type_timeseries/common/get_last_value'; function getColors(props) { const { model, visData } = props; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/markdown/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/markdown/vis.js index e20f3d3fbaebc6..a8063390854504 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/markdown/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/markdown/vis.js @@ -26,7 +26,7 @@ import { Markdown } from '../../../../../kibana_react/public'; import { ErrorComponent } from '../../error'; import { replaceVars } from '../../lib/replace_vars'; import { convertSeriesToVars } from '../../lib/convert_series_to_vars'; -import { isBackgroundInverted } from '../../../../common/set_is_reversed'; +import { isBackgroundInverted } from '../../../lib/set_is_reversed'; const getMarkdownId = id => `markdown-${id}`; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/metric/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/metric/vis.js index f463a4494a189f..4a907a7b2078d0 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/metric/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/metric/vis.js @@ -23,8 +23,8 @@ import { visWithSplits } from '../../vis_with_splits'; import { createTickFormatter } from '../../lib/tick_formatter'; import _, { get, isUndefined, assign, includes, pick } from 'lodash'; import { Metric } from '../../../visualizations/views/metric'; -import { getLastValue } from '../../../../common/get_last_value'; -import { isBackgroundInverted } from '../../../../common/set_is_reversed'; +import { getLastValue } from '../../../../../../../plugins/vis_type_timeseries/common/get_last_value'; +import { isBackgroundInverted } from '../../../lib/set_is_reversed'; function getColors(props) { const { model, visData } = props; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/is_sortable.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/is_sortable.js index 887652a67f406d..b44c94131348d4 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/is_sortable.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/is_sortable.js @@ -17,7 +17,7 @@ * under the License. */ -import { basicAggs } from '../../../../common/basic_aggs'; +import { basicAggs } from '../../../../../../../plugins/vis_type_timeseries/common/basic_aggs'; export function isSortable(metric) { return basicAggs.includes(metric.type); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js index a82d5bdb1588c7..94f4506cd01726 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js @@ -22,14 +22,14 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { npStart } from 'ui/new_platform'; import { createTickFormatter } from '../../lib/tick_formatter'; -import { calculateLabel } from '../../../../common/calculate_label'; +import { calculateLabel } from '../../../../../../../plugins/vis_type_timeseries/common/calculate_label'; import { isSortable } from './is_sortable'; import { EuiToolTip, EuiIcon } from '@elastic/eui'; import { replaceVars } from '../../lib/replace_vars'; import { fieldFormats } from '../../../../../../../plugins/data/public'; import { FormattedMessage } from '@kbn/i18n/react'; -import { METRIC_TYPES } from '../../../../common/metric_types'; +import { METRIC_TYPES } from '../../../../../../../plugins/vis_type_timeseries/common/metric_types'; function getColor(rules, colorKey, value) { let color; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/series.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/series.js index 226aded390508c..27a84d9ba40b98 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/series.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/series.js @@ -35,7 +35,7 @@ import { import { Split } from '../../split'; import { createTextHandler } from '../../lib/create_text_handler'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -import { PANEL_TYPES } from '../../../../common/panel_types'; +import { PANEL_TYPES } from '../../../../../../../plugins/vis_type_timeseries/common/panel_types'; const TimeseriesSeriesUI = injectI18n(function(props) { const { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js index d269d7c3546ec7..5243f5f92a621a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js @@ -34,7 +34,7 @@ import { getAxisLabelString } from '../../lib/get_axis_label_string'; import { getInterval } from '../../lib/get_interval'; import { areFieldsDifferent } from '../../lib/charts'; import { createXaxisFormatter } from '../../lib/create_xaxis_formatter'; -import { isBackgroundDark } from '../../../../common/set_is_reversed'; +import { isBackgroundDark } from '../../../lib/set_is_reversed'; import { STACKED_OPTIONS } from '../../../visualizations/constants'; export class TimeseriesVisualization extends Component { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/top_n/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/top_n/vis.js index 7d09f33acdecce..2ebc60325a4251 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/top_n/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/top_n/vis.js @@ -19,8 +19,8 @@ import { createTickFormatter } from '../../lib/tick_formatter'; import { TopN } from '../../../visualizations/views/top_n'; -import { getLastValue } from '../../../../common/get_last_value'; -import { isBackgroundInverted } from '../../../../common/set_is_reversed'; +import { getLastValue } from '../../../../../../../plugins/vis_type_timeseries/common/get_last_value'; +import { isBackgroundInverted } from '../../../lib/set_is_reversed'; import { replaceVars } from '../../lib/replace_vars'; import PropTypes from 'prop-types'; import React from 'react'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_with_splits.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_with_splits.js index 91d53b9c2e1dbd..e36910d9081b3c 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_with_splits.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_with_splits.js @@ -20,7 +20,7 @@ import React from 'react'; import { getDisplayName } from './lib/get_display_name'; import { last, findIndex, first } from 'lodash'; -import { calculateLabel } from '../../common/calculate_label'; +import { calculateLabel } from '../../../../../plugins/vis_type_timeseries/common/calculate_label'; export function visWithSplits(WrappedComponent) { function SplitVisComponent(props) { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/lib/check_ui_restrictions.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/check_ui_restrictions.js index 1fade6ebe98495..5d18c0a2f09cd1 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/lib/check_ui_restrictions.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/check_ui_restrictions.js @@ -18,7 +18,10 @@ */ import { get } from 'lodash'; -import { RESTRICTIONS_KEYS, DEFAULT_UI_RESTRICTION } from '../../common/ui_restrictions'; +import { + RESTRICTIONS_KEYS, + DEFAULT_UI_RESTRICTION, +} from '../../../../../plugins/vis_type_timeseries/common/ui_restrictions'; /** * Generic method for checking all types of the UI Restrictions diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js index 21c12b07ff47fe..68e694f23fa7f9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js @@ -19,7 +19,7 @@ import { kfetch } from 'ui/kfetch'; import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; -import { extractIndexPatterns } from '../../common/extract_index_patterns'; +import { extractIndexPatterns } from '../../../../../plugins/vis_type_timeseries/common/extract_index_patterns'; export async function fetchFields(indexPatterns = ['*']) { const patterns = Array.isArray(indexPatterns) ? indexPatterns : [indexPatterns]; diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/set_is_reversed.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/set_is_reversed.js similarity index 92% rename from src/legacy/core_plugins/vis_type_timeseries/common/set_is_reversed.js rename to src/legacy/core_plugins/vis_type_timeseries/public/lib/set_is_reversed.js index b633d004b9705c..9f66bcd1619166 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/common/set_is_reversed.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/set_is_reversed.js @@ -18,9 +18,9 @@ */ import color from 'color'; -import chrome from '../../../ui/public/chrome'; +import { getUISettings } from '../services'; -const IS_DARK_THEME = chrome.getUiSettingsClient().get('theme:darkMode'); +const isDarkTheme = () => getUISettings().get('theme:darkMode'); /** * Returns true if the color that is passed has low luminosity @@ -34,7 +34,7 @@ const isColorDark = c => { * Defaults to checking `theme:darkMode`. */ export const isThemeDark = currentTheme => { - let themeIsDark = currentTheme || IS_DARK_THEME; + let themeIsDark = currentTheme || isDarkTheme(); // If passing a string, check the luminosity if (typeof currentTheme === 'string') { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js index 2dbcdc4749a660..2992549d38e308 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js @@ -17,7 +17,7 @@ * under the License. */ -import { GTE_INTERVAL_RE } from '../../common/interval_regexp'; +import { GTE_INTERVAL_RE } from '../../../../../plugins/vis_type_timeseries/common/interval_regexp'; import { i18n } from '@kbn/i18n'; import { parseInterval } from '../../../../../plugins/data/public'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts index e7684cd21b7976..22d2b3b10e566a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts @@ -26,7 +26,7 @@ import { metricsRequestHandler } from './request_handler'; // @ts-ignore import { EditorController } from './editor_controller'; // @ts-ignore -import { PANEL_TYPES } from '../common/panel_types'; +import { PANEL_TYPES } from '../../../../plugins/vis_type_timeseries/common/panel_types'; export const metricsVisDefinition = { name: 'metrics', diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/gauge.js b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/gauge.js index 3be2e9daed58c6..b518665e5ece42 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/gauge.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/gauge.js @@ -21,8 +21,8 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import classNames from 'classnames'; -import { isBackgroundInverted, isBackgroundDark } from '../../../common/set_is_reversed'; -import { getLastValue } from '../../../common/get_last_value'; +import { isBackgroundInverted, isBackgroundDark } from '../../lib/set_is_reversed'; +import { getLastValue } from '../../../../../../plugins/vis_type_timeseries/common/get_last_value'; import { getValueBy } from '../lib/get_value_by'; import { GaugeVis } from './gauge_vis'; import reactcss from 'reactcss'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/metric.js b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/metric.js index 004d59efca3330..5524e17d106e49 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/metric.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/metric.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import _ from 'lodash'; -import { getLastValue } from '../../../common/get_last_value'; +import { getLastValue } from '../../../../../../plugins/vis_type_timeseries/common/get_last_value'; import reactcss from 'reactcss'; import { calculateCoordinates } from '../lib/calculate_coordinates'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/top_n.js b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/top_n.js index 5734d101a09d20..99e9cc0b1c2183 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/top_n.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/top_n.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { getLastValue } from '../../../common/get_last_value'; +import { getLastValue } from '../../../../../../plugins/vis_type_timeseries/common/get_last_value'; import reactcss from 'reactcss'; const RENDER_MODES = { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/init.ts b/src/legacy/core_plugins/vis_type_timeseries/server/init.ts deleted file mode 100644 index ae6eebc00fc1ba..00000000000000 --- a/src/legacy/core_plugins/vis_type_timeseries/server/init.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// @ts-ignore -import { fieldsRoutes } from './routes/fields'; -// @ts-ignore -import { visDataRoutes } from './routes/vis'; -// @ts-ignore -import { SearchStrategiesRegister } from './lib/search_strategies/search_strategies_register'; -// @ts-ignore -import { getVisData } from './lib/get_vis_data'; -import { Framework } from '../../../../plugins/vis_type_timeseries/server'; -import { ValidationTelemetryServiceSetup } from '../../../../plugins/vis_type_timeseries/server'; - -export const init = async ( - framework: Framework, - __LEGACY: any, - validationTelemetry: ValidationTelemetryServiceSetup -) => { - const { core } = framework; - const router = core.http.createRouter(); - - visDataRoutes(router, framework, validationTelemetry); - - // [LEGACY_TODO] - fieldsRoutes(__LEGACY.server); - SearchStrategiesRegister.init(__LEGACY.server); -}; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_fields.js b/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_fields.js deleted file mode 100644 index 361ce132f17359..00000000000000 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_fields.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { SearchStrategiesRegister } from './search_strategies/search_strategies_register'; -import { uniq } from 'lodash'; -import { getIndexPatternObject } from './vis_data/helpers/get_index_pattern'; -import { isNestedField } from '../../../../../plugins/data/server'; - -export async function getFields(req) { - const indexPattern = req.query.index; - const { indexPatternString } = await getIndexPatternObject(req, indexPattern); - const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy( - req, - indexPatternString - ); - - const fields = ( - await searchStrategy.getFieldsForWildcard(req, indexPatternString, capabilities) - ).filter(field => field.aggregatable && !isNestedField(field)); - - return uniq(fields, field => field.name); -} diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_index_pattern_service.js b/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_index_pattern_service.js deleted file mode 100644 index 54e90ab7dd9b7f..00000000000000 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_index_pattern_service.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IndexPatternsFetcher } from '../../../../../plugins/data/server/'; -export const getIndexPatternService = { - assign: 'indexPatternsService', - method(req) { - const dataCluster = req.server.plugins.elasticsearch.getCluster('data'); - const callDataCluster = (...args) => { - return dataCluster.callWithRequest(req, ...args); - }; - return new IndexPatternsFetcher(callDataCluster); - }, -}; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/index.js b/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/index.js deleted file mode 100644 index 512894f30a619d..00000000000000 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { SearchStrategiesRegister } from './search_strategies_register'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.js b/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.js deleted file mode 100644 index 794e92a1954a92..00000000000000 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export class AbstractSearchStrategy { - constructor(server, callWithRequestFactory, SearchRequest) { - this.getCallWithRequestInstance = req => callWithRequestFactory(server, req); - - this.getSearchRequest = req => { - const callWithRequest = this.getCallWithRequestInstance(req); - - return new SearchRequest(req, callWithRequest); - }; - } - - async getFieldsForWildcard(req, indexPattern) { - const { indexPatternsService } = req.pre; - - return await indexPatternsService.getFieldsForWildcard({ - pattern: indexPattern, - }); - } - - checkForViability() { - throw new TypeError('Must override method'); - } -} diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/__snapshots__/model_options.test.js.snap b/src/plugins/vis_type_timeseries/common/__snapshots__/model_options.test.js.snap similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/__snapshots__/model_options.test.js.snap rename to src/plugins/vis_type_timeseries/common/__snapshots__/model_options.test.js.snap diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/agg_lookup.js b/src/plugins/vis_type_timeseries/common/agg_lookup.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/agg_lookup.js rename to src/plugins/vis_type_timeseries/common/agg_lookup.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/agg_lookup.test.js b/src/plugins/vis_type_timeseries/common/agg_lookup.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/agg_lookup.test.js rename to src/plugins/vis_type_timeseries/common/agg_lookup.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/basic_aggs.js b/src/plugins/vis_type_timeseries/common/basic_aggs.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/basic_aggs.js rename to src/plugins/vis_type_timeseries/common/basic_aggs.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/calculate_label.js b/src/plugins/vis_type_timeseries/common/calculate_label.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/calculate_label.js rename to src/plugins/vis_type_timeseries/common/calculate_label.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/calculate_label.test.js b/src/plugins/vis_type_timeseries/common/calculate_label.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/calculate_label.test.js rename to src/plugins/vis_type_timeseries/common/calculate_label.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/extract_index_patterns.js b/src/plugins/vis_type_timeseries/common/extract_index_patterns.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/extract_index_patterns.js rename to src/plugins/vis_type_timeseries/common/extract_index_patterns.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/extract_index_patterns.test.js b/src/plugins/vis_type_timeseries/common/extract_index_patterns.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/extract_index_patterns.test.js rename to src/plugins/vis_type_timeseries/common/extract_index_patterns.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/field_types.js b/src/plugins/vis_type_timeseries/common/field_types.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/field_types.js rename to src/plugins/vis_type_timeseries/common/field_types.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/get_last_value.js b/src/plugins/vis_type_timeseries/common/get_last_value.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/get_last_value.js rename to src/plugins/vis_type_timeseries/common/get_last_value.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/get_last_value.test.js b/src/plugins/vis_type_timeseries/common/get_last_value.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/get_last_value.test.js rename to src/plugins/vis_type_timeseries/common/get_last_value.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/interval_regexp.js b/src/plugins/vis_type_timeseries/common/interval_regexp.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/interval_regexp.js rename to src/plugins/vis_type_timeseries/common/interval_regexp.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/interval_regexp.test.js b/src/plugins/vis_type_timeseries/common/interval_regexp.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/interval_regexp.test.js rename to src/plugins/vis_type_timeseries/common/interval_regexp.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/metric_types.js b/src/plugins/vis_type_timeseries/common/metric_types.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/metric_types.js rename to src/plugins/vis_type_timeseries/common/metric_types.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/model_options.js b/src/plugins/vis_type_timeseries/common/model_options.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/model_options.js rename to src/plugins/vis_type_timeseries/common/model_options.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/model_options.test.js b/src/plugins/vis_type_timeseries/common/model_options.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/model_options.test.js rename to src/plugins/vis_type_timeseries/common/model_options.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/panel_types.js b/src/plugins/vis_type_timeseries/common/panel_types.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/panel_types.js rename to src/plugins/vis_type_timeseries/common/panel_types.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/timerange_data_modes.js b/src/plugins/vis_type_timeseries/common/timerange_data_modes.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/timerange_data_modes.js rename to src/plugins/vis_type_timeseries/common/timerange_data_modes.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/to_percentile_number.js b/src/plugins/vis_type_timeseries/common/to_percentile_number.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/to_percentile_number.js rename to src/plugins/vis_type_timeseries/common/to_percentile_number.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/common/ui_restrictions.js b/src/plugins/vis_type_timeseries/common/ui_restrictions.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/common/ui_restrictions.js rename to src/plugins/vis_type_timeseries/common/ui_restrictions.js diff --git a/src/plugins/vis_type_timeseries/server/index.ts b/src/plugins/vis_type_timeseries/server/index.ts index dfb2394af237bf..fa74b6e9659710 100644 --- a/src/plugins/vis_type_timeseries/server/index.ts +++ b/src/plugins/vis_type_timeseries/server/index.ts @@ -32,6 +32,13 @@ export type VisTypeTimeseriesConfig = TypeOf; export { ValidationTelemetryServiceSetup } from './validation_telemetry'; +// @ts-ignore +export { AbstractSearchStrategy } from './lib/search_strategies/strategies/abstract_search_strategy'; +// @ts-ignore +export { AbstractSearchRequest } from './lib/search_strategies/search_requests/abstract_request'; +// @ts-ignore +export { DefaultSearchCapabilities } from './lib/search_strategies/default_search_capabilities'; + export function plugin(initializerContext: PluginInitializerContext) { return new VisTypeTimeseriesPlugin(initializerContext); } diff --git a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts new file mode 100644 index 00000000000000..8eca30dae7773a --- /dev/null +++ b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts @@ -0,0 +1,89 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { uniq } from 'lodash'; +import { first, map } from 'rxjs/operators'; +import { KibanaRequest, RequestHandlerContext } from 'kibana/server'; + +// @ts-ignore +import { getIndexPatternObject } from './vis_data/helpers/get_index_pattern'; +import { isNestedField } from '../../../data/server'; +import { Framework } from '../plugin'; +import { FieldDescriptor, IndexPatternsFetcher } from '../../../data/server'; +import { ReqFacade } from './search_strategies/strategies/abstract_search_strategy'; + +export async function getFields( + requestContext: RequestHandlerContext, + request: KibanaRequest, + framework: Framework, + indexPattern: string +) { + // NOTE / TODO: This facade has been put in place to make migrating to the New Platform easier. It + // removes the need to refactor many layers of dependencies on "req", and instead just augments the top + // level object passed from here. The layers should be refactored fully at some point, but for now + // this works and we are still using the New Platform services for these vis data portions. + const reqFacade: ReqFacade = { + ...request, + framework, + payload: {}, + pre: { + indexPatternsService: new IndexPatternsFetcher( + requestContext.core.elasticsearch.dataClient.callAsCurrentUser + ), + }, + getUiSettingsService: () => requestContext.core.uiSettings.client, + getSavedObjectsClient: () => requestContext.core.savedObjects.client, + server: { + plugins: { + elasticsearch: { + getCluster: () => { + return { + callWithRequest: async (req: any, endpoint: string, params: any) => { + return await requestContext.core.elasticsearch.dataClient.callAsCurrentUser( + endpoint, + params + ); + }, + }; + }, + }, + }, + }, + getEsShardTimeout: async () => { + return await framework.globalConfig$ + .pipe( + first(), + map(config => config.elasticsearch.shardTimeout.asMilliseconds()) + ) + .toPromise(); + }, + }; + const { indexPatternString } = await getIndexPatternObject(reqFacade, indexPattern); + const { + searchStrategy, + capabilities, + } = (await framework.searchStrategyRegistry.getViableStrategy(reqFacade, indexPatternString))!; + + const fields = ((await searchStrategy.getFieldsForWildcard( + reqFacade, + indexPatternString, + capabilities + )) as FieldDescriptor[]).filter(field => field.aggregatable && !isNestedField(field)); + + return uniq(fields, field => field.name); +} diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_vis_data.ts b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts similarity index 87% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/get_vis_data.ts rename to src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts index 58e624fa134429..aef831eaad4302 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/get_vis_data.ts +++ b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts @@ -17,11 +17,12 @@ * under the License. */ -import { RequestHandlerContext } from 'src/core/server'; +import { FakeRequest, RequestHandlerContext } from 'kibana/server'; import _ from 'lodash'; import { first, map } from 'rxjs/operators'; import { getPanelData } from './vis_data/get_panel_data'; -import { Framework } from '../../../../../plugins/vis_type_timeseries/server'; +import { Framework } from '../index'; +import { ReqFacade } from './search_strategies/strategies/abstract_search_strategy'; interface GetVisDataResponse { [key: string]: GetVisDataPanel; @@ -56,15 +57,18 @@ export type GetVisData = ( export function getVisData( requestContext: RequestHandlerContext, - options: GetVisDataOptions, + request: FakeRequest & { body: GetVisDataOptions }, framework: Framework ): Promise { // NOTE / TODO: This facade has been put in place to make migrating to the New Platform easier. It // removes the need to refactor many layers of dependencies on "req", and instead just augments the top // level object passed from here. The layers should be refactored fully at some point, but for now // this works and we are still using the New Platform services for these vis data portions. - const reqFacade: any = { - payload: options, + const reqFacade: ReqFacade = { + ...request, + framework, + pre: {}, + payload: request.body, getUiSettingsService: () => requestContext.core.uiSettings.client, getSavedObjectsClient: () => requestContext.core.savedObjects.client, server: { @@ -92,7 +96,7 @@ export function getVisData( .toPromise(); }, }; - const promises = reqFacade.payload.panels.map(getPanelData(reqFacade)); + const promises = (reqFacade.payload as GetVisDataOptions).panels.map(getPanelData(reqFacade)); return Promise.all(promises).then(res => { return res.reduce((acc, data) => { return _.assign(acc as any, data); diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/default_search_capabilities.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/index.ts b/src/plugins/vis_type_timeseries/server/lib/search_strategies/index.ts similarity index 87% rename from src/legacy/core_plugins/vis_type_timeseries/server/index.ts rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/index.ts index c010628ca04bfd..d53683882252b5 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/index.ts +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { init } from './init'; -export { getVisData, GetVisData, GetVisDataOptions } from './lib/get_vis_data'; +export { SearchStrategyRegistry } from './search_strategy_registry'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/abstract_request.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/abstract_request.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/abstract_request.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/abstract_request.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/abstract_request.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/abstract_request.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/abstract_request.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/abstract_request.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/multi_search_request.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/multi_search_request.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/multi_search_request.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/multi_search_request.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/multi_search_request.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/multi_search_request.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/multi_search_request.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/multi_search_request.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/search_request.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/search_request.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/search_request.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/search_request.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/search_request.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/search_request.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/search_request.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/search_request.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/single_search_request.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/single_search_request.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/single_search_request.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/single_search_request.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/single_search_request.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/single_search_request.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/searh_requests/single_search_request.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_requests/single_search_request.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts similarity index 61% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts index e03d776b8ee0c7..ecd09653b3b489 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.test.js +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts @@ -16,10 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { SearchStrategiesRegister } from './search_strategies_register'; + +import { SearchStrategyRegistry } from './search_strategy_registry'; +// @ts-ignore import { AbstractSearchStrategy } from './strategies/abstract_search_strategy'; +// @ts-ignore import { DefaultSearchStrategy } from './strategies/default_search_strategy'; -import { AbstractSearchRequest } from './searh_requests/abstract_request'; +// @ts-ignore import { DefaultSearchCapabilities } from './default_search_capabilities'; class MockSearchStrategy extends AbstractSearchStrategy { @@ -31,34 +34,21 @@ class MockSearchStrategy extends AbstractSearchStrategy { } } -describe('SearchStrategiesRegister', () => { - let server; - let strategies; - let anotherSearchStrategy; +describe('SearchStrategyRegister', () => { + let registry: SearchStrategyRegistry; beforeAll(() => { - server = { - expose: jest.fn((strategy, func) => { - server[strategy] = func; - }), - }; - strategies = [ - ['AbstractSearchStrategy', AbstractSearchStrategy], - ['AbstractSearchRequest', AbstractSearchRequest], - ['DefaultSearchCapabilities', DefaultSearchCapabilities], - ['addSearchStrategy', expect.any(Function)], - ]; - - SearchStrategiesRegister.init(server); + registry = new SearchStrategyRegistry(); }); test('should init strategies register', () => { - expect(server.expose.mock.calls).toEqual(strategies); - expect(server.addSearchStrategy()[0] instanceof DefaultSearchStrategy).toBe(true); + expect( + registry.addStrategy({} as AbstractSearchStrategy)[0] instanceof DefaultSearchStrategy + ).toBe(true); }); test('should not add a strategy if it is not an instance of AbstractSearchStrategy', () => { - const addedStrategies = server.addSearchStrategy({}); + const addedStrategies = registry.addStrategy({} as AbstractSearchStrategy); expect(addedStrategies.length).toEqual(1); expect(addedStrategies[0] instanceof DefaultSearchStrategy).toBe(true); @@ -68,18 +58,15 @@ describe('SearchStrategiesRegister', () => { const req = {}; const indexPattern = '*'; - const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy( - req, - indexPattern - ); + const { searchStrategy, capabilities } = (await registry.getViableStrategy(req, indexPattern))!; expect(searchStrategy instanceof DefaultSearchStrategy).toBe(true); expect(capabilities instanceof DefaultSearchCapabilities).toBe(true); }); test('should add a strategy if it is an instance of AbstractSearchStrategy', () => { - anotherSearchStrategy = new MockSearchStrategy(); - const addedStrategies = server.addSearchStrategy(anotherSearchStrategy); + const anotherSearchStrategy = new MockSearchStrategy({}, {} as any, {}); + const addedStrategies = registry.addStrategy(anotherSearchStrategy); expect(addedStrategies.length).toEqual(2); expect(addedStrategies[0] instanceof AbstractSearchStrategy).toBe(true); @@ -88,13 +75,12 @@ describe('SearchStrategiesRegister', () => { test('should return a MockSearchStrategy instance', async () => { const req = {}; const indexPattern = '*'; + const anotherSearchStrategy = new MockSearchStrategy({}, {} as any, {}); + registry.addStrategy(anotherSearchStrategy); - const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy( - req, - indexPattern - ); + const { searchStrategy, capabilities } = (await registry.getViableStrategy(req, indexPattern))!; - expect(searchStrategy instanceof AbstractSearchStrategy).toBe(true); + expect(searchStrategy instanceof MockSearchStrategy).toBe(true); expect(capabilities).toEqual({}); }); }); diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts similarity index 57% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts index 5fbb4060862a42..6fbed1ddfba0f3 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_register.js +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts @@ -16,34 +16,32 @@ * specific language governing permissions and limitations * under the License. */ + import { AbstractSearchStrategy } from './strategies/abstract_search_strategy'; -import { AbstractSearchRequest } from './searh_requests/abstract_request'; +// @ts-ignore import { DefaultSearchStrategy } from './strategies/default_search_strategy'; -import { DefaultSearchCapabilities } from './default_search_capabilities'; - +// @ts-ignore import { extractIndexPatterns } from '../../../common/extract_index_patterns'; -const strategies = []; +export type RequestFacade = any; +export type Panel = any; -const addStrategy = searchStrategy => { - if (searchStrategy instanceof AbstractSearchStrategy) { - strategies.unshift(searchStrategy); - } - return strategies; -}; +export class SearchStrategyRegistry { + private strategies: AbstractSearchStrategy[] = []; -export class SearchStrategiesRegister { - static init(server) { - server.expose('AbstractSearchStrategy', AbstractSearchStrategy); - server.expose('AbstractSearchRequest', AbstractSearchRequest); - server.expose('DefaultSearchCapabilities', DefaultSearchCapabilities); - server.expose('addSearchStrategy', searchStrategy => addStrategy(searchStrategy)); + constructor() { + this.addStrategy(new DefaultSearchStrategy()); + } - addStrategy(new DefaultSearchStrategy(server)); + public addStrategy(searchStrategy: AbstractSearchStrategy) { + if (searchStrategy instanceof AbstractSearchStrategy) { + this.strategies.unshift(searchStrategy); + } + return this.strategies; } - static async getViableStrategy(req, indexPattern) { - for (const searchStrategy of strategies) { + async getViableStrategy(req: RequestFacade, indexPattern: string) { + for (const searchStrategy of this.strategies) { const { isViable, capabilities } = await searchStrategy.checkForViability(req, indexPattern); if (isViable) { @@ -55,9 +53,9 @@ export class SearchStrategiesRegister { } } - static async getViableStrategyForPanel(req, panel) { + async getViableStrategyForPanel(req: RequestFacade, panel: Panel) { const indexPattern = extractIndexPatterns(panel).join(','); - return SearchStrategiesRegister.getViableStrategy(req, indexPattern); + return this.getViableStrategy(req, indexPattern); } } diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts new file mode 100644 index 00000000000000..4fd4ac251fa3e8 --- /dev/null +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + APICaller, + FakeRequest, + IUiSettingsClient, + SavedObjectsClientContract, +} from 'kibana/server'; +import { Framework } from '../../../plugin'; +import { IndexPatternsFetcher } from '../../../../../data/server'; + +/** + * ReqFacade is a regular KibanaRequest object extended with additional service + * references to ensure backwards compatibility for existing integrations. + * + * This will be replaced by standard KibanaRequest and RequestContext objects in a later version. + */ +export type ReqFacade = FakeRequest & { + framework: Framework; + payload: unknown; + pre: { + indexPatternsService?: IndexPatternsFetcher; + }; + getUiSettingsService: () => IUiSettingsClient; + getSavedObjectsClient: () => SavedObjectsClientContract; + server: { + plugins: { + elasticsearch: { + getCluster: () => { + callWithRequest: (req: ReqFacade, endpoint: string, params: any) => Promise; + }; + }; + }; + }; + getEsShardTimeout: () => Promise; +}; + +export class AbstractSearchStrategy { + public getCallWithRequestInstance: (req: ReqFacade) => APICaller; + public getSearchRequest: (req: ReqFacade) => any; + + constructor( + server: any, + callWithRequestFactory: (server: any, req: ReqFacade) => APICaller, + SearchRequest: any + ) { + this.getCallWithRequestInstance = req => callWithRequestFactory(server, req); + + this.getSearchRequest = req => { + const callWithRequest = this.getCallWithRequestInstance(req); + + return new SearchRequest(req, callWithRequest); + }; + } + + async getFieldsForWildcard(req: ReqFacade, indexPattern: string, capabilities: any) { + const { indexPatternsService } = req.pre; + + return await indexPatternsService!.getFieldsForWildcard({ + pattern: indexPattern, + }); + } + + checkForViability( + req: ReqFacade, + indexPattern: string + ): { isViable: boolean; capabilities: any } { + throw new TypeError('Must override method'); + } +} diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js similarity index 95% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js index fba67f448e7849..63f2911ce11187 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.js @@ -17,7 +17,7 @@ * under the License. */ import { AbstractSearchStrategy } from './abstract_search_strategy'; -import { SearchRequest } from '../searh_requests/search_request'; +import { SearchRequest } from '../search_requests/search_request'; import { DefaultSearchCapabilities } from '../default_search_capabilities'; const callWithRequestFactory = (server, request) => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.js b/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.js rename to src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations/build_request_body.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/build_request_body.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations/build_request_body.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/build_request_body.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations/get_request_params.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/get_request_params.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/annorations/get_request_params.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/get_request_params.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts b/src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts rename to src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts b/src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts rename to src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js similarity index 96% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js index 898ff837d4a012..8b8c31912f168c 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.js @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { handleAnnotationResponse } from './response_processors/annotations/'; -import { getAnnotationRequestParams } from './annorations/get_request_params'; +import { handleAnnotationResponse } from './response_processors/annotations'; +import { getAnnotationRequestParams } from './annotations/get_request_params'; import { getLastSeriesTimestamp } from './helpers/timestamp'; function validAnnotation(annotation) { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.d.ts b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.d.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.d.ts rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.d.ts diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_panel_data.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js similarity index 91% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js index b4eb9e6b108ff7..1efeccb4b5701f 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.js @@ -20,15 +20,14 @@ import { getSeriesRequestParams } from './series/get_request_params'; import { handleResponseBody } from './series/handle_response_body'; import { handleErrorResponse } from './handle_error_response'; import { getAnnotations } from './get_annotations'; -import { SearchStrategiesRegister } from '../search_strategies/search_strategies_register'; import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; import { getActiveSeries } from './helpers/get_active_series'; export async function getSeriesData(req, panel) { - const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategyForPanel( - req, - panel - ); + const { + searchStrategy, + capabilities, + } = await req.framework.searchStrategyRegistry.getViableStrategyForPanel(req, panel); const searchRequest = searchStrategy.getSearchRequest(req); const esQueryConfig = await getEsQueryConfig(req); const meta = { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js similarity index 90% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js index 2c92692d2bd1ff..1d1c2459079591 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.js @@ -20,16 +20,16 @@ import { buildRequestBody } from './table/build_request_body'; import { handleErrorResponse } from './handle_error_response'; import { get } from 'lodash'; import { processBucket } from './table/process_bucket'; -import { SearchStrategiesRegister } from '../search_strategies/search_strategies_register'; import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; import { getIndexPatternObject } from './helpers/get_index_pattern'; export async function getTableData(req, panel) { const panelIndexPattern = panel.index_pattern; - const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy( - req, - panelIndexPattern - ); + + const { + searchStrategy, + capabilities, + } = await req.framework.searchStrategyRegistry.getViableStrategy(req, panelIndexPattern); const searchRequest = searchStrategy.getSearchRequest(req); const esQueryConfig = await getEsQueryConfig(req); const { indexPatternObject } = await getIndexPatternObject(req, panelIndexPattern); diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/calculate_auto.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/calculate_auto.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/calculate_auto.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/calculate_auto.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js similarity index 97% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js index de23b90b21d6c0..3ec5454fcee778 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.js @@ -24,7 +24,7 @@ import { convertIntervalToUnit, ASCENDING_UNIT_ORDER, } from './unit_to_seconds'; -import { getTimerangeDuration } from '../helpers/get_timerange'; +import { getTimerangeDuration } from './get_timerange'; import { INTERVAL_STRING_RE, GTE_INTERVAL_RE } from '../../../../common/interval_regexp'; const calculateBucketData = (timeInterval, capabilities) => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_shard_timeout.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_index_pattern.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_index_pattern.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_index_pattern.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_index_pattern.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_bucket.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_settings.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js similarity index 94% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js index 5a763ce35e35e1..995790c590e424 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { dateHistogramInterval } from '../../../../../../data/server'; +import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { getTimerange } from '../../helpers/get_timerange'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js similarity index 97% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js index d6514e3bc45d4d..a4817dac9bd186 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.js @@ -19,7 +19,7 @@ import { getBucketSize } from '../../helpers/get_bucket_size'; import { getTimerange } from '../../helpers/get_timerange'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function query(req, panel, annotation, esQueryConfig, indexPattern, capabilities) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js similarity index 96% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js index 3b55e2bf4c1516..48da5ac19aa3ae 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { dateHistogramInterval } from '../../../../../../data/server'; +import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { offsetTime } from '../../offset_time'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js similarity index 96% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js index 53f894322a8e08..e5b81912f286ef 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js @@ -19,7 +19,7 @@ import { offsetTime } from '../../offset_time'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function query(req, panel, series, esQueryConfig, indexPatternObject) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js similarity index 94% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js index 1548c9e17c2e18..80b4ef70a3f085 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function splitByFilter(req, panel, series, esQueryConfig, indexPattern) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js similarity index 94% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js index 4295bceed43cc7..d023c28cdb25ef 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function splitByFilters(req, panel, series, esQueryConfig, indexPattern) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js similarity index 96% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js index 183785fab9be17..f33ce145aa2309 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { dateHistogramInterval } from '../../../../../../data/server'; +import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { isLastValueTimerangeMode } from '../../helpers/get_timerange_mode'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js similarity index 96% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js index 9d46c212e05bd1..d8d948e01cccd9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.js @@ -18,7 +18,7 @@ */ import { getTimerange } from '../../helpers/get_timerange'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function query(req, panel, esQueryConfig, indexPatternObject) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js similarity index 95% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js index 17f99ea431fd37..35036abed320f9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function splitByEverything(req, panel, esQueryConfig, indexPattern) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js similarity index 95% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js index 042e4d98e27675..5b7ae735cd50f5 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.js @@ -18,7 +18,7 @@ */ import { set } from 'lodash'; -import { esQuery } from '../../../../../../../../plugins/data/server'; +import { esQuery } from '../../../../../../data/server'; export function splitByTerms(req, panel, esQueryConfig, indexPattern) { return next => doc => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts b/src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts rename to src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts b/src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts similarity index 95% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts rename to src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts index 85e1f8f7eb12b2..9d8f3fca789f09 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts @@ -19,7 +19,7 @@ import { buildProcessorFunction } from '../build_processor_function'; // @ts-ignore -import { processors } from '../request_processors/series'; +import { processors } from '../request_processors/series/index'; /** * Builds series request body diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.js diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.js similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.js rename to src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.js diff --git a/src/plugins/vis_type_timeseries/server/plugin.ts b/src/plugins/vis_type_timeseries/server/plugin.ts index dcd0cd500bbc31..6ef6362c6e37be 100644 --- a/src/plugins/vis_type_timeseries/server/plugin.ts +++ b/src/plugins/vis_type_timeseries/server/plugin.ts @@ -24,19 +24,19 @@ import { Plugin, RequestHandlerContext, Logger, + IRouter, + FakeRequest, } from 'src/core/server'; import { Observable } from 'rxjs'; import { Server } from 'hapi'; -import { once } from 'lodash'; import { VisTypeTimeseriesConfig } from '.'; -import { - init, - getVisData, - GetVisData, - GetVisDataOptions, -} from '../../../legacy/core_plugins/vis_type_timeseries/server'; -import { ValidationTelemetryService } from './validation_telemetry/validation_telemetry_service'; +import { getVisData, GetVisData, GetVisDataOptions } from './lib/get_vis_data'; +import { ValidationTelemetryService } from './validation_telemetry'; import { UsageCollectionSetup } from '../../usage_collection/server'; +import { visDataRoutes } from './routes/vis'; +// @ts-ignore +import { fieldsRoutes } from './routes/fields'; +import { SearchStrategyRegistry } from './lib/search_strategies'; export interface LegacySetup { server: Server; @@ -47,15 +47,12 @@ interface VisTypeTimeseriesPluginSetupDependencies { } export interface VisTypeTimeseriesSetup { - /** @deprecated */ - __legacy: { - config$: Observable; - registerLegacyAPI: (__LEGACY: LegacySetup) => void; - }; getVisData: ( requestContext: RequestHandlerContext, + fakeRequest: FakeRequest, options: GetVisDataOptions ) => ReturnType; + addSearchStrategy: SearchStrategyRegistry['addStrategy']; } export interface Framework { @@ -64,6 +61,8 @@ export interface Framework { config$: Observable; globalConfig$: PluginInitializerContext['config']['legacy']['globalConfig$']; logger: Logger; + router: IRouter; + searchStrategyRegistry: SearchStrategyRegistry; } export class VisTypeTimeseriesPlugin implements Plugin { @@ -79,6 +78,9 @@ export class VisTypeTimeseriesPlugin implements Plugin { const config$ = this.initializerContext.config.create(); // Global config contains things like the ES shard timeout const globalConfig$ = this.initializerContext.config.legacy.globalConfig$; + const router = core.http.createRouter(); + + const searchStrategyRegistry = new SearchStrategyRegistry(); const framework: Framework = { core, @@ -86,23 +88,29 @@ export class VisTypeTimeseriesPlugin implements Plugin { config$, globalConfig$, logger, + router, + searchStrategyRegistry, }; - return { - __legacy: { - config$, - registerLegacyAPI: once(async (__LEGACY: LegacySetup) => { - const validationTelemetrySetup = await this.validationTelementryService.setup(core, { - ...plugins, - globalConfig$, - }); + (async () => { + const validationTelemetry = await this.validationTelementryService.setup(core, { + ...plugins, + globalConfig$, + }); + visDataRoutes(router, framework, validationTelemetry); - await init(framework, __LEGACY, validationTelemetrySetup); - }), - }, - getVisData: async (requestContext: RequestHandlerContext, options: GetVisDataOptions) => { - return await getVisData(requestContext, options, framework); + fieldsRoutes(framework); + })(); + + return { + getVisData: async ( + requestContext: RequestHandlerContext, + fakeRequest: FakeRequest, + options: GetVisDataOptions + ) => { + return await getVisData(requestContext, { ...fakeRequest, body: options }, framework); }, + addSearchStrategy: searchStrategyRegistry.addStrategy.bind(searchStrategyRegistry), }; } diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/routes/fields.js b/src/plugins/vis_type_timeseries/server/routes/fields.ts similarity index 54% rename from src/legacy/core_plugins/vis_type_timeseries/server/routes/fields.js rename to src/plugins/vis_type_timeseries/server/routes/fields.ts index d984868afb0b04..255c85c9eefa7f 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/routes/fields.js +++ b/src/plugins/vis_type_timeseries/server/routes/fields.ts @@ -17,26 +17,35 @@ * under the License. */ +import { isBoom } from 'boom'; +import { schema } from '@kbn/config-schema'; import { getFields } from '../lib/get_fields'; -import { getIndexPatternService } from '../lib/get_index_pattern_service'; +import { Framework } from '../plugin'; -export const fieldsRoutes = server => { - server.route({ - config: { - pre: [getIndexPatternService], +export const fieldsRoutes = (framework: Framework) => { + framework.router.get( + { + path: '/api/metrics/fields', + validate: { + query: schema.object({ index: schema.string() }), + }, }, - path: '/api/metrics/fields', - method: 'GET', - handler: async req => { + async (context, req, res) => { try { - return await getFields(req); + return res.ok({ body: await getFields(context, req, framework, req.query.index) }); } catch (err) { - if (err.isBoom && err.status === 401) { - return err; + if (isBoom(err) && err.output.statusCode === 401) { + return res.customError({ + body: err.output.payload, + statusCode: err.output.statusCode, + headers: err.output.headers, + }); } - return []; + return res.ok({ + body: [], + }); } - }, - }); + } + ); }; diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/routes/post_vis_schema.ts b/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_timeseries/server/routes/post_vis_schema.ts rename to src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts diff --git a/src/legacy/core_plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_type_timeseries/server/routes/vis.ts similarity index 85% rename from src/legacy/core_plugins/vis_type_timeseries/server/routes/vis.ts rename to src/plugins/vis_type_timeseries/server/routes/vis.ts index 32e87f5a3f666a..e2d1e4d114ad5d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/server/routes/vis.ts +++ b/src/plugins/vis_type_timeseries/server/routes/vis.ts @@ -17,14 +17,11 @@ * under the License. */ -import { IRouter } from 'kibana/server'; +import { IRouter, KibanaRequest } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { getVisData } from '../lib/get_vis_data'; +import { getVisData, GetVisDataOptions } from '../lib/get_vis_data'; import { visPayloadSchema } from './post_vis_schema'; -import { - Framework, - ValidationTelemetryServiceSetup, -} from '../../../../../plugins/vis_type_timeseries/server'; +import { Framework, ValidationTelemetryServiceSetup } from '../index'; const escapeHatch = schema.object({}, { allowUnknowns: true }); @@ -52,7 +49,11 @@ export const visDataRoutes = ( ); } try { - const results = await getVisData(requestContext, request.body, framework); + const results = await getVisData( + requestContext, + request as KibanaRequest<{}, {}, GetVisDataOptions>, + framework + ); return response.ok({ body: results }); } catch (error) { return response.internalError({ diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 4409667d8390a4..4b1aa774a523ff 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -241,6 +241,7 @@ export class KibanaFramework { public async makeTSVBRequest( requestContext: RequestHandlerContext, + rawRequest: KibanaRequest, model: TSVBMetricModel, timerange: { min: number; max: number }, filters: any[] @@ -254,6 +255,6 @@ export class KibanaFramework { panels: [model], filters, }; - return getVisData(requestContext, options); + return getVisData(requestContext, rawRequest, options); } } diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index eb5ac05644a227..5a5f9d0f8f5293 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -51,7 +51,7 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { } const requests = options.metrics.map(metricId => - this.makeTSVBRequest(metricId, options, nodeField, requestContext) + this.makeTSVBRequest(metricId, options, nodeField, requestContext, rawRequest) ); return Promise.all(requests) @@ -93,7 +93,8 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { metricId: InventoryMetric, options: InfraMetricsRequestOptions, nodeField: string, - requestContext: RequestHandlerContext + requestContext: RequestHandlerContext, + rawRequest: KibanaRequest ) { const createTSVBModel = get(metrics, ['tsvb', metricId]) as TSVBMetricModelCreator | undefined; if (!createTSVBModel) { @@ -152,6 +153,6 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { ? [{ match: { [model.map_field_to]: id } }] : [{ match: { [nodeField]: id } }]; - return this.framework.makeTSVBRequest(requestContext, model, timerange, filters); + return this.framework.makeTSVBRequest(requestContext, rawRequest, model, timerange, filters); } } diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts index 8ab3fdccbe72b8..347feca67aa99c 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts @@ -76,7 +76,13 @@ export const populateSeriesWithTSVBData = ( } // Get TSVB results using the model, timerange and filters - const tsvbResults = await framework.makeTSVBRequest(requestContext, model, timerange, filters); + const tsvbResults = await framework.makeTSVBRequest( + requestContext, + request, + model, + timerange, + filters + ); // If there is no data `custom` will not exist. if (!tsvbResults.custom) { diff --git a/x-pack/legacy/plugins/rollup/index.js b/x-pack/legacy/plugins/rollup/index.js index a10407b19fa93b..cace3bba1592b9 100644 --- a/x-pack/legacy/plugins/rollup/index.js +++ b/x-pack/legacy/plugins/rollup/index.js @@ -60,7 +60,7 @@ export function rollup(kibana) { server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); } - registerRollupSearchStrategy(this.kbnServer, server); + registerRollupSearchStrategy(this.kbnServer); }, }); } diff --git a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js index 537c5cf45ad61e..284151d404a470 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js +++ b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js @@ -8,10 +8,10 @@ import { once } from 'lodash'; import { elasticsearchJsPlugin } from '../../client/elasticsearch_rollup'; const callWithRequest = once(server => { - const config = { plugins: [elasticsearchJsPlugin] }; - const cluster = server.plugins.elasticsearch.createCluster('rollup', config); - - return cluster.callWithRequest; + const client = server.newPlatform.setup.core.elasticsearch.createClient('rollup', { + plugins: [elasticsearchJsPlugin], + }); + return (request, ...args) => client.asScoped(request).callAsCurrentUser(...args); }); export const callWithRequestFactory = (server, request) => { diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js index 5d732c8e7fbaa5..fe65a7f1f30e90 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js @@ -6,19 +6,19 @@ import { getRollupSearchStrategy } from './rollup_search_strategy'; import { getRollupSearchRequest } from './rollup_search_request'; import { getRollupSearchCapabilities } from './rollup_search_capabilities'; +import { + AbstractSearchRequest, + DefaultSearchCapabilities, + AbstractSearchStrategy, +} from '../../../../../../../src/plugins/vis_type_timeseries/server'; -export const registerRollupSearchStrategy = (kbnServer, server) => +export const registerRollupSearchStrategy = kbnServer => kbnServer.afterPluginsInit(() => { - if (!server.plugins.metrics) { + if (!kbnServer.newPlatform.setup.plugins.metrics) { return; } - const { - addSearchStrategy, - AbstractSearchRequest, - AbstractSearchStrategy, - DefaultSearchCapabilities, - } = server.plugins.metrics; + const { addSearchStrategy } = kbnServer.newPlatform.setup.plugins.metrics; const RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest); const RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities); @@ -28,5 +28,5 @@ export const registerRollupSearchStrategy = (kbnServer, server) => RollupSearchCapabilities ); - addSearchStrategy(new RollupSearchStrategy(server)); + addSearchStrategy(new RollupSearchStrategy(kbnServer)); }); diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js index 5a1e4f27b1453c..acd016d75f97ed 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js @@ -14,6 +14,9 @@ describe('Register Rollup Search Strategy', () => { kbnServer = { afterPluginsInit, + newPlatform: { + setup: { plugins: {} }, + }, }; metrics = { @@ -25,27 +28,22 @@ describe('Register Rollup Search Strategy', () => { }); test('should run initialization on "afterPluginsInit" hook', () => { - registerRollupSearchStrategy(kbnServer, { - plugins: {}, - }); + registerRollupSearchStrategy(kbnServer); expect(kbnServer.afterPluginsInit).toHaveBeenCalled(); }); test('should run initialization if metrics plugin available', () => { - registerRollupSearchStrategy(kbnServer, { - plugins: { - metrics, - }, + registerRollupSearchStrategy({ + ...kbnServer, + newPlatform: { setup: { plugins: { metrics } } }, }); expect(metrics.addSearchStrategy).toHaveBeenCalled(); }); test('should not run initialization if metrics plugin unavailable', () => { - registerRollupSearchStrategy(kbnServer, { - plugins: {}, - }); + registerRollupSearchStrategy(kbnServer); expect(metrics.addSearchStrategy).not.toHaveBeenCalled(); }); From ef8dba30498b347179b695d17a760a2b0087b27c Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 30 Jan 2020 17:07:45 +0100 Subject: [PATCH 17/69] [ML] conditional rison encoding for query params (#56380) --- .../public/application/util/url_state.test.ts | 2 +- .../ml/public/application/util/url_state.ts | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/ml/public/application/util/url_state.test.ts b/x-pack/legacy/plugins/ml/public/application/util/url_state.test.ts index 91bbef2dba6c2b..0813f2e3da97fd 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/url_state.test.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/url_state.test.ts @@ -75,7 +75,7 @@ describe('useUrlState', () => { expect(mockHistoryPush).toHaveBeenCalledWith({ search: - '_a=%28mlExplorerFilter%3A%28%29%2CmlExplorerSwimlane%3A%28viewByFieldName%3Aaction%29%2Cquery%3A%28%29%29&_g=%28ml%3A%28jobIds%3A%21%28dec-2%29%29%2CrefreshInterval%3A%28display%3AOff%2Cpause%3A%21f%2Cvalue%3A0%29%2Ctime%3A%28from%3A%272019-01-01T00%3A03%3A40.000Z%27%2Cmode%3Aabsolute%2Cto%3A%272019-08-30T11%3A55%3A07.000Z%27%29%29&savedSearchId=%27571aaf70-4c88-11e8-b3d7-01146121b73d%27', + '_a=%28mlExplorerFilter%3A%28%29%2CmlExplorerSwimlane%3A%28viewByFieldName%3Aaction%29%2Cquery%3A%28%29%29&_g=%28ml%3A%28jobIds%3A%21%28dec-2%29%29%2CrefreshInterval%3A%28display%3AOff%2Cpause%3A%21f%2Cvalue%3A0%29%2Ctime%3A%28from%3A%272019-01-01T00%3A03%3A40.000Z%27%2Cmode%3Aabsolute%2Cto%3A%272019-08-30T11%3A55%3A07.000Z%27%29%29&savedSearchId=571aaf70-4c88-11e8-b3d7-01146121b73d', }); }); }); diff --git a/x-pack/legacy/plugins/ml/public/application/util/url_state.ts b/x-pack/legacy/plugins/ml/public/application/util/url_state.ts index 546944b1a33bff..e7d5a94e2694fb 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/url_state.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/url_state.ts @@ -18,14 +18,26 @@ import { getNestedProperty } from './object_utils'; export type SetUrlState = (attribute: string | Dictionary, value?: any) => void; export type UrlState = [Dictionary, SetUrlState]; -const decodedParams = new Set(['_a', '_g']); +/** + * Set of URL query parameters that require the rison serialization. + */ +const risonSerializedParams = new Set(['_a', '_g']); + +/** + * Checks if the URL query parameter requires rison serialization. + * @param queryParam + */ +function isRisonSerializationRequired(queryParam: string): boolean { + return risonSerializedParams.has(queryParam); +} + export function getUrlState(search: string): Dictionary { const urlState: Dictionary = {}; const parsedQueryString = queryString.parse(search); try { Object.keys(parsedQueryString).forEach(a => { - if (decodedParams.has(a)) { + if (isRisonSerializationRequired(a)) { urlState[a] = decode(parsedQueryString[a]) as Dictionary; } else { urlState[a] = parsedQueryString[a]; @@ -75,7 +87,11 @@ export const useUrlState = (accessor: string): UrlState => { const oldLocationSearch = queryString.stringify(parsedQueryString, { encode: false }); Object.keys(urlState).forEach(a => { - parsedQueryString[a] = encode(urlState[a]); + if (isRisonSerializationRequired(a)) { + parsedQueryString[a] = encode(urlState[a]); + } else { + parsedQueryString[a] = urlState[a]; + } }); const newLocationSearch = queryString.stringify(parsedQueryString, { encode: false }); From c28f7bacdad6f4ea2ecacc6fa48e03ae6493ae1e Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Thu, 30 Jan 2020 11:13:14 -0500 Subject: [PATCH 18/69] [Monitoring] Change all configs to `monitoring.*` (#56215) * Revert "Revert "[Monitoring] Change all configs to `monitoring.*`" (#56214)" This reverts commit bd08eb7efcd0df87581d91b6c69e270f4fe5670d. * Fix missing config changes * More fixes * Doc changes Co-authored-by: Elastic Machine --- docs/settings/monitoring-settings.asciidoc | 32 +++---- .../config/deprecation/core_deprecations.ts | 50 ++++++++++ x-pack/legacy/plugins/monitoring/config.js | 96 +++++++++---------- .../legacy/plugins/monitoring/deprecations.js | 4 +- x-pack/legacy/plugins/monitoring/index.js | 34 +++---- .../flyout/__snapshots__/flyout.test.js.snap | 8 +- ...isable_internal_collection_instructions.js | 4 +- .../cluster_alerts/alerts_cluster_search.js | 2 +- .../verify_monitoring_license.js | 2 +- .../es_client/__tests__/instantiate_client.js | 6 +- .../parse_elasticsearch_config.test.ts | 4 +- .../es_client/parse_elasticsearch_config.ts | 2 +- .../server/init_monitoring_xpack_info.js | 2 +- .../server/kibana_monitoring/bulk_uploader.js | 2 +- .../__tests__/get_default_admin_email.js | 12 +-- .../collectors/get_settings_collector.js | 4 +- .../collectors/ops_buffer/ops_buffer.js | 2 +- .../server/kibana_monitoring/init.js | 2 +- .../server/lib/__tests__/ccs_utils.js | 8 +- .../monitoring/server/lib/apm/get_apms.js | 2 +- .../server/lib/apm/get_apms_for_clusters.js | 2 +- .../monitoring/server/lib/apm/get_stats.js | 2 +- .../monitoring/server/lib/beats/get_beats.js | 2 +- .../lib/beats/get_beats_for_clusters.js | 2 +- .../server/lib/beats/get_latest_stats.js | 2 +- .../monitoring/server/lib/beats/get_stats.js | 2 +- .../monitoring/server/lib/ccs_utils.js | 2 +- .../lib/cluster/get_clusters_from_request.js | 2 +- .../server/lib/cluster/get_clusters_stats.js | 2 +- .../lib/details/__test__/get_metrics.test.js | 2 +- .../server/lib/details/get_metrics.js | 2 +- .../server/lib/elasticsearch/get_ml_jobs.js | 2 +- .../lib/elasticsearch/indices/get_indices.js | 2 +- .../nodes/get_nodes/get_nodes.js | 6 +- .../nodes/get_nodes/get_paginated_nodes.js | 4 +- .../get_indices_unassigned_shard_stats.js | 2 +- .../shards/get_nodes_shard_count.js | 2 +- .../shards/get_shard_allocation.js | 2 +- .../shards/get_shard_stat_aggs.js | 2 +- .../server/lib/kibana/get_kibanas.js | 2 +- .../lib/kibana/get_kibanas_for_clusters.js | 2 +- .../monitoring/server/lib/logs/get_logs.js | 2 +- .../lib/logstash/get_logstash_for_clusters.js | 6 +- .../server/lib/logstash/get_nodes.js | 2 +- .../lib/logstash/get_paginated_pipelines.js | 2 +- .../server/lib/logstash/get_pipeline.js | 2 +- .../get_pipeline_stats_aggregation.js | 2 +- .../lib/logstash/get_pipeline_versions.js | 2 +- .../lib/logstash/get_pipeline_vertex.js | 2 +- .../get_pipeline_vertex_stats_aggregation.js | 2 +- .../plugins/monitoring/server/plugin.js | 16 ++-- .../server/routes/api/v1/elasticsearch/ccr.js | 2 +- .../api/v1/elasticsearch/node_detail.js | 2 +- .../server/routes/api/v1/logstash/node.js | 4 +- .../pipelines/cluster_pipeline_ids.js | 2 +- .../telemetry_collection/get_cluster_uuids.ts | 2 +- .../telemetry_collection/get_es_stats.js | 2 +- .../get_high_level_stats.js | 2 +- .../legacy/plugins/monitoring/ui_exports.js | 2 +- 59 files changed, 212 insertions(+), 170 deletions(-) diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc index 8f445ff25218bc..8586d26e9a07ad 100644 --- a/docs/settings/monitoring-settings.asciidoc +++ b/docs/settings/monitoring-settings.asciidoc @@ -14,7 +14,7 @@ built-in `elastic` user has this role. You can adjust how monitoring data is collected from {kib} and displayed in {kib} by configuring settings in the -`kibana.yml` file. There are also `xpack.monitoring.elasticsearch.*` settings, +`kibana.yml` file. There are also `monitoring.ui.elasticsearch.*` settings, which support the same values as <>. To control how data is collected from your {es} nodes, you configure @@ -31,20 +31,20 @@ For more information, see [[monitoring-general-settings]] ==== General monitoring settings -`xpack.monitoring.enabled`:: +`monitoring.enabled`:: Set to `true` (default) to enable the {monitor-features} in {kib}. Unlike the -`xpack.monitoring.ui.enabled` setting, when this setting is `false`, the +`monitoring.ui.enabled` setting, when this setting is `false`, the monitoring back-end does not run and {kib} stats are not sent to the monitoring cluster. -`xpack.monitoring.elasticsearch.hosts`:: +`monitoring.ui.elasticsearch.hosts`:: Specifies the location of the {es} cluster where your monitoring data is stored. By default, this is the same as `elasticsearch.hosts`. This setting enables you to use a single {kib} instance to search and visualize data in your production cluster as well as monitor data sent to a dedicated monitoring cluster. -`xpack.monitoring.elasticsearch.username`:: +`monitoring.ui.elasticsearch.username`:: Specifies the username used by {kib} monitoring to establish a persistent connection in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} monitoring cluster. @@ -55,7 +55,7 @@ both the {es} monitoring cluster and the {es} production cluster. If not set, {kib} uses the value of the `elasticsearch.username` setting. -`xpack.monitoring.elasticsearch.password`:: +`monitoring.ui.elasticsearch.password`:: Specifies the password used by {kib} monitoring to establish a persistent connection in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} monitoring cluster. @@ -66,7 +66,7 @@ both the {es} monitoring cluster and the {es} production cluster. If not set, {kib} uses the value of the `elasticsearch.password` setting. -`xpack.monitoring.elasticsearch.pingTimeout`:: +`monitoring.ui.elasticsearch.pingTimeout`:: Specifies the time in milliseconds to wait for {es} to respond to internal health checks. By default, it matches the `elasticsearch.pingTimeout` setting, which has a default value of `30000`. @@ -77,11 +77,11 @@ which has a default value of `30000`. These settings control how data is collected from {kib}. -`xpack.monitoring.kibana.collection.enabled`:: +`monitoring.kibana.collection.enabled`:: Set to `true` (default) to enable data collection from the {kib} NodeJS server for {kib} Dashboards to be featured in the Monitoring. -`xpack.monitoring.kibana.collection.interval`:: +`monitoring.kibana.collection.interval`:: Specifies the number of milliseconds to wait in between data sampling on the {kib} NodeJS server for the metrics that are displayed in the {kib} dashboards. Defaults to `10000` (10 seconds). @@ -96,24 +96,24 @@ However, the defaults work best in most circumstances. For more information about configuring {kib}, see {kibana-ref}/settings.html[Setting Kibana Server Properties]. -`xpack.monitoring.elasticsearch.logFetchCount`:: +`monitoring.ui.elasticsearch.logFetchCount`:: Specifies the number of log entries to display in the Monitoring UI. Defaults to `10`. The maximum value is `50`. -`xpack.monitoring.max_bucket_size`:: +`monitoring.ui.max_bucket_size`:: Specifies the number of term buckets to return out of the overall terms list when performing terms aggregations to retrieve index and node metrics. For more information about the `size` parameter, see {ref}/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-size[Terms Aggregation]. Defaults to `10000`. -`xpack.monitoring.min_interval_seconds`:: +`monitoring.ui.min_interval_seconds`:: Specifies the minimum number of seconds that a time bucket in a chart can represent. Defaults to 10. If you modify the -`xpack.monitoring.collection.interval` in `elasticsearch.yml`, use the same +`monitoring.ui.collection.interval` in `elasticsearch.yml`, use the same value in this setting. -`xpack.monitoring.ui.enabled`:: +`monitoring.ui.enabled`:: Set to `false` to hide the Monitoring UI in {kib}. The monitoring back-end continues to run as an agent for sending {kib} stats to the monitoring cluster. Defaults to `true`. @@ -127,7 +127,7 @@ better decisions about your container performance, rather than guessing based on the overall machine performance. If you are not running your applications in a container, then Cgroup statistics are not useful. -`xpack.monitoring.ui.container.elasticsearch.enabled`:: +`monitoring.ui.container.elasticsearch.enabled`:: For {es} clusters that are running in containers, this setting changes the *Node Listing* to display the CPU utilization based on the reported Cgroup @@ -135,7 +135,7 @@ statistics. It also adds the calculated Cgroup CPU utilization to the *Node Overview* page instead of the overall operating system's CPU utilization. Defaults to `false`. -`xpack.monitoring.ui.container.logstash.enabled`:: +`monitoring.ui.container.logstash.enabled`:: For {ls} nodes that are running in containers, this setting changes the {ls} *Node Listing* to display the CPU utilization diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index c63c9384da9d83..3aa7f9e2aa8ad2 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -119,6 +119,56 @@ export const coreDeprecationProvider: ConfigDeprecationProvider = ({ renameFromRoot('xpack.telemetry.config', 'telemetry.config'), renameFromRoot('xpack.telemetry.banner', 'telemetry.banner'), renameFromRoot('xpack.telemetry.url', 'telemetry.url'), + // Monitoring renames + // TODO: Remove these from here once the monitoring plugin is migrated to NP + renameFromRoot('xpack.monitoring.enabled', 'monitoring.enabled'), + renameFromRoot('xpack.monitoring.ui.enabled', 'monitoring.ui.enabled'), + renameFromRoot( + 'xpack.monitoring.kibana.collection.enabled', + 'monitoring.kibana.collection.enabled' + ), + renameFromRoot('xpack.monitoring.max_bucket_size', 'monitoring.ui.max_bucket_size'), + renameFromRoot('xpack.monitoring.min_interval_seconds', 'monitoring.ui.min_interval_seconds'), + renameFromRoot( + 'xpack.monitoring.show_license_expiration', + 'monitoring.ui.show_license_expiration' + ), + renameFromRoot( + 'xpack.monitoring.ui.container.elasticsearch.enabled', + 'monitoring.ui.container.elasticsearch.enabled' + ), + renameFromRoot( + 'xpack.monitoring.ui.container.logstash.enabled', + 'monitoring.ui.container.logstash.enabled' + ), + renameFromRoot( + 'xpack.monitoring.tests.cloud_detector.enabled', + 'monitoring.tests.cloud_detector.enabled' + ), + renameFromRoot( + 'xpack.monitoring.kibana.collection.interval', + 'monitoring.kibana.collection.interval' + ), + renameFromRoot('xpack.monitoring.elasticsearch.hosts', 'monitoring.ui.elasticsearch.hosts'), + renameFromRoot('xpack.monitoring.elasticsearch.username', 'monitoring.ui.elasticsearch.username'), + renameFromRoot('xpack.monitoring.elasticsearch.password', 'monitoring.ui.elasticsearch.password'), + renameFromRoot( + 'xpack.monitoring.xpack_api_polling_frequency_millis', + 'monitoring.xpack_api_polling_frequency_millis' + ), + renameFromRoot( + 'xpack.monitoring.cluster_alerts.email_notifications.enabled', + 'monitoring.cluster_alerts.email_notifications.enabled' + ), + renameFromRoot( + 'xpack.monitoring.cluster_alerts.email_notifications.email_address', + 'monitoring.cluster_alerts.email_notifications.email_address' + ), + renameFromRoot('xpack.monitoring.ccs.enabled', 'monitoring.ui.ccs.enabled'), + renameFromRoot( + 'xpack.monitoring.elasticsearch.logFetchCount', + 'monitoring.ui.elasticsearch.logFetchCount' + ), configPathDeprecation, dataPathDeprecation, rewriteBasePathDeprecation, diff --git a/x-pack/legacy/plugins/monitoring/config.js b/x-pack/legacy/plugins/monitoring/config.js index 91c1ee99a0b2e4..778b656c056f20 100644 --- a/x-pack/legacy/plugins/monitoring/config.js +++ b/x-pack/legacy/plugins/monitoring/config.js @@ -15,12 +15,12 @@ export const config = Joi => { const DEFAULT_REQUEST_HEADERS = ['authorization']; return Joi.object({ - ccs: Joi.object({ - enabled: Joi.boolean().default(true), - }).default(), enabled: Joi.boolean().default(true), ui: Joi.object({ enabled: Joi.boolean().default(true), + ccs: Joi.object({ + enabled: Joi.boolean().default(true), + }).default(), container: Joi.object({ elasticsearch: Joi.object({ enabled: Joi.boolean().default(false), @@ -29,6 +29,51 @@ export const config = Joi => { enabled: Joi.boolean().default(false), }).default(), }).default(), + max_bucket_size: Joi.number().default(10000), + min_interval_seconds: Joi.number().default(10), + show_license_expiration: Joi.boolean().default(true), + elasticsearch: Joi.object({ + customHeaders: Joi.object().default({}), + logQueries: Joi.boolean().default(false), + requestHeadersWhitelist: Joi.array() + .items() + .single() + .default(DEFAULT_REQUEST_HEADERS), + sniffOnStart: Joi.boolean().default(false), + sniffInterval: Joi.number() + .allow(false) + .default(false), + sniffOnConnectionFault: Joi.boolean().default(false), + hosts: Joi.array() + .items(Joi.string().uri({ scheme: ['http', 'https'] })) + .single(), // if empty, use Kibana's connection config + username: Joi.string(), + password: Joi.string(), + requestTimeout: Joi.number().default(30000), + pingTimeout: Joi.number().default(30000), + ssl: Joi.object({ + verificationMode: Joi.string() + .valid('none', 'certificate', 'full') + .default('full'), + certificateAuthorities: Joi.array() + .single() + .items(Joi.string()), + certificate: Joi.string(), + key: Joi.string(), + keyPassphrase: Joi.string(), + keystore: Joi.object({ + path: Joi.string(), + password: Joi.string(), + }).default(), + truststore: Joi.object({ + path: Joi.string(), + password: Joi.string(), + }).default(), + alwaysPresentCertificate: Joi.boolean().default(false), + }).default(), + apiVersion: Joi.string().default('master'), + logFetchCount: Joi.number().default(10), + }).default(), }).default(), kibana: Joi.object({ collection: Joi.object({ @@ -46,56 +91,11 @@ export const config = Joi => { xpack_api_polling_frequency_millis: Joi.number().default( XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS ), - max_bucket_size: Joi.number().default(10000), - min_interval_seconds: Joi.number().default(10), - show_license_expiration: Joi.boolean().default(true), agent: Joi.object({ interval: Joi.string() .regex(/[\d\.]+[yMwdhms]/) .default('10s'), }).default(), - elasticsearch: Joi.object({ - customHeaders: Joi.object().default({}), - logQueries: Joi.boolean().default(false), - requestHeadersWhitelist: Joi.array() - .items() - .single() - .default(DEFAULT_REQUEST_HEADERS), - sniffOnStart: Joi.boolean().default(false), - sniffInterval: Joi.number() - .allow(false) - .default(false), - sniffOnConnectionFault: Joi.boolean().default(false), - hosts: Joi.array() - .items(Joi.string().uri({ scheme: ['http', 'https'] })) - .single(), // if empty, use Kibana's connection config - username: Joi.string(), - password: Joi.string(), - requestTimeout: Joi.number().default(30000), - pingTimeout: Joi.number().default(30000), - ssl: Joi.object({ - verificationMode: Joi.string() - .valid('none', 'certificate', 'full') - .default('full'), - certificateAuthorities: Joi.array() - .single() - .items(Joi.string()), - certificate: Joi.string(), - key: Joi.string(), - keyPassphrase: Joi.string(), - keystore: Joi.object({ - path: Joi.string(), - password: Joi.string(), - }).default(), - truststore: Joi.object({ - path: Joi.string(), - password: Joi.string(), - }).default(), - alwaysPresentCertificate: Joi.boolean().default(false), - }).default(), - apiVersion: Joi.string().default('master'), - logFetchCount: Joi.number().default(10), - }).default(), tests: Joi.object({ cloud_detector: Joi.object({ enabled: Joi.boolean().default(true), diff --git a/x-pack/legacy/plugins/monitoring/deprecations.js b/x-pack/legacy/plugins/monitoring/deprecations.js index c3b2b70690f33b..6e35e86dd9d718 100644 --- a/x-pack/legacy/plugins/monitoring/deprecations.js +++ b/x-pack/legacy/plugins/monitoring/deprecations.js @@ -28,7 +28,7 @@ export const deprecations = () => { } }, (settings, log) => { - const fromPath = 'xpack.monitoring.elasticsearch'; + const fromPath = 'monitoring.elasticsearch'; const es = get(settings, 'elasticsearch'); if (es) { if (es.username === 'elastic') { @@ -39,7 +39,7 @@ export const deprecations = () => { } }, (settings, log) => { - const fromPath = 'xpack.monitoring.elasticsearch.ssl'; + const fromPath = 'monitoring.elasticsearch.ssl'; const ssl = get(settings, 'elasticsearch.ssl'); if (ssl) { if (ssl.key !== undefined && ssl.certificate === undefined) { diff --git a/x-pack/legacy/plugins/monitoring/index.js b/x-pack/legacy/plugins/monitoring/index.js index 8e0201bea710bc..ca595836133c2c 100644 --- a/x-pack/legacy/plugins/monitoring/index.js +++ b/x-pack/legacy/plugins/monitoring/index.js @@ -20,31 +20,31 @@ export const monitoring = kibana => new kibana.Plugin({ require: ['kibana', 'elasticsearch', 'xpack_main'], id: 'monitoring', - configPrefix: 'xpack.monitoring', + configPrefix: 'monitoring', publicDir: resolve(__dirname, 'public'), init(server) { const configs = [ - 'xpack.monitoring.ui.enabled', - 'xpack.monitoring.kibana.collection.enabled', - 'xpack.monitoring.max_bucket_size', - 'xpack.monitoring.min_interval_seconds', + 'monitoring.ui.enabled', + 'monitoring.kibana.collection.enabled', + 'monitoring.ui.max_bucket_size', + 'monitoring.ui.min_interval_seconds', 'kibana.index', - 'xpack.monitoring.show_license_expiration', - 'xpack.monitoring.ui.container.elasticsearch.enabled', - 'xpack.monitoring.ui.container.logstash.enabled', - 'xpack.monitoring.tests.cloud_detector.enabled', - 'xpack.monitoring.kibana.collection.interval', - 'xpack.monitoring.elasticsearch.hosts', - 'xpack.monitoring.elasticsearch', - 'xpack.monitoring.xpack_api_polling_frequency_millis', + 'monitoring.ui.show_license_expiration', + 'monitoring.ui.container.elasticsearch.enabled', + 'monitoring.ui.container.logstash.enabled', + 'monitoring.tests.cloud_detector.enabled', + 'monitoring.kibana.collection.interval', + 'monitoring.ui.elasticsearch.hosts', + 'monitoring.ui.elasticsearch', + 'monitoring.xpack_api_polling_frequency_millis', 'server.uuid', 'server.name', 'server.host', 'server.port', - 'xpack.monitoring.cluster_alerts.email_notifications.enabled', - 'xpack.monitoring.cluster_alerts.email_notifications.email_address', - 'xpack.monitoring.ccs.enabled', - 'xpack.monitoring.elasticsearch.logFetchCount', + 'monitoring.cluster_alerts.email_notifications.enabled', + 'monitoring.cluster_alerts.email_notifications.email_address', + 'monitoring.ui.ccs.enabled', + 'monitoring.ui.elasticsearch.logFetchCount', ]; const serverConfig = server.config(); diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap index 7f48f3386b1807..eb1c65c6a696da 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap @@ -1174,7 +1174,7 @@ exports[`Flyout kibana part two should show instructions to disable internal col isCopyable={true} language="bash" > - xpack.monitoring.kibana.collection.enabled: false + monitoring.kibana.collection.enabled: false - xpack.monitoring.enabled + monitoring.enabled , "defaultValue": true @@ -2091,7 +2091,7 @@ exports[`Flyout should show a restart warning for restarting the primary Kibana isCopyable={true} language="bash" > - xpack.monitoring.kibana.collection.enabled: false + monitoring.kibana.collection.enabled: false - xpack.monitoring.enabled + monitoring.enabled , "defaultValue": true diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js index 9326156c1ac36e..5f7f97b74e8717 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js +++ b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js @@ -61,7 +61,7 @@ export function getKibanaInstructionsForDisablingInternalCollection(product, met - xpack.monitoring.kibana.collection.enabled: false + monitoring.kibana.collection.enabled: false @@ -70,7 +70,7 @@ export function getKibanaInstructionsForDisablingInternalCollection(product, met id="xpack.monitoring.metricbeatMigration.kibanaInstructions.disableInternalCollection.note" defaultMessage="For {config}, leave the default value of ({defaultValue})." values={{ - config: xpack.monitoring.enabled, + config: monitoring.enabled, defaultValue: true, }} /> diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js index 0c9fb4bd04ee77..eff9875d794adf 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js +++ b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js @@ -157,7 +157,7 @@ export function alertsClusterSearch(req, alertsIndex, cluster, checkLicense, opt if (prodLicenseInfo.clusterAlerts.enabled) { const config = req.server.config(); - const size = options.size || config.get('xpack.monitoring.max_bucket_size'); + const size = options.size || config.get('monitoring.ui.max_bucket_size'); const params = { index: alertsIndex, diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js index 9cc67e11c28d57..e94f4e08fbdb18 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js +++ b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js @@ -19,7 +19,7 @@ export function verifyMonitoringLicense(server) { const config = server.config(); // if cluster alerts are enabled, then ensure that we can use it according to the license - if (config.get('xpack.monitoring.cluster_alerts.enabled')) { + if (config.get('monitoring.cluster_alerts.enabled')) { const xpackInfo = get(server.plugins.monitoring, 'info'); if (xpackInfo) { const monitoringCluster = xpackInfo.feature('monitoring').getLicenseCheckResults(); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js b/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js index 6844bd5febf8ee..88cf9734d5f57d 100644 --- a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js +++ b/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js @@ -11,8 +11,8 @@ import { exposeClient, hasMonitoringCluster } from '../instantiate_client'; function getMockServerFromConnectionUrl(monitoringClusterUrl) { const server = { - xpack: { - monitoring: { + monitoring: { + ui: { elasticsearch: { hosts: monitoringClusterUrl ? [monitoringClusterUrl] : [], username: 'monitoring-user-internal-test', @@ -27,7 +27,7 @@ function getMockServerFromConnectionUrl(monitoringClusterUrl) { }; return { - elasticsearchConfig: server.xpack.monitoring.elasticsearch, + elasticsearchConfig: server.monitoring.ui.elasticsearch, elasticsearchPlugin: { getCluster: sinon .stub() diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts index c6f4e0fa685045..8d9b5335732c0c 100644 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts +++ b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts @@ -168,14 +168,14 @@ describe('throws when config is invalid', () => { it('throws if key and keystore.path are both specified', () => { const value = { ssl: { key: 'foo', keystore: { path: 'bar' } } }; expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"[config validation of [xpack.monitoring.elasticsearch].ssl]: cannot use [key] when [keystore.path] is specified"` + `"[config validation of [monitoring.ui.elasticsearch].ssl]: cannot use [key] when [keystore.path] is specified"` ); }); it('throws if certificate and keystore.path are both specified', () => { const value = { ssl: { certificate: 'foo', keystore: { path: 'bar' } } }; expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"[config validation of [xpack.monitoring.elasticsearch].ssl]: cannot use [certificate] when [keystore.path] is specified"` + `"[config validation of [monitoring.ui.elasticsearch].ssl]: cannot use [certificate] when [keystore.path] is specified"` ); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts index 70e6235602b5b9..728b3433bf06c0 100644 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts +++ b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts @@ -7,7 +7,7 @@ import { readFileSync } from 'fs'; import { readPkcs12Truststore, readPkcs12Keystore } from '../../../../../../src/core/utils'; -const KEY = 'xpack.monitoring.elasticsearch'; +const KEY = 'monitoring.ui.elasticsearch'; /* * Parse a config object's Elasticsearch configuration, reading any diff --git a/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js b/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js index b43430ead23b0f..ba07f512de896a 100644 --- a/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js +++ b/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js @@ -15,7 +15,7 @@ export const initMonitoringXpackInfo = async ({ config, xpackMainPlugin, expose, const xpackInfo = hasMonitoringCluster(config) ? xpackMainPlugin.createXPackInfo({ clusterSource: 'monitoring', - pollFrequencyInMillis: config.get('xpack.monitoring.xpack_api_polling_frequency_millis'), + pollFrequencyInMillis: config.get('monitoring.xpack_api_polling_frequency_millis'), }) : xpackMainPlugin.info; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js index 5e0d8aa4be1fdc..cf68ec073bebc8 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js @@ -24,7 +24,7 @@ const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG]; * NOTE: internal collection will be removed in 7.0 * * Depends on - * - 'xpack.monitoring.kibana.collection.enabled' config + * - 'monitoring.kibana.collection.enabled' config * - monitoring enabled in ES (checked against xpack_main.info license info change) * The dependencies are handled upstream * - Ops Events - essentially Kibana's /api/status diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js index 96dc461c03fd30..10f52a82a830cf 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js @@ -14,14 +14,10 @@ describe('getSettingsCollector / getDefaultAdminEmail', () => { function setup({ enabled = true, adminEmail = null } = {}) { const config = { get: sinon.stub() }; - config.get - .withArgs('xpack.monitoring.cluster_alerts.email_notifications.enabled') - .returns(enabled); + config.get.withArgs('monitoring.cluster_alerts.email_notifications.enabled').returns(enabled); if (adminEmail) { - config.get - .withArgs(`xpack.monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`) - .returns(adminEmail); + config.get.withArgs(`monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`).returns(adminEmail); } config.get.withArgs('kibana.index').returns('.kibana'); @@ -31,7 +27,7 @@ describe('getSettingsCollector / getDefaultAdminEmail', () => { return config; } - describe('xpack.monitoring.cluster_alerts.email_notifications.enabled = false', () => { + describe('monitoring.cluster_alerts.email_notifications.enabled = false', () => { it('returns null when email is defined', async () => { const config = setup({ enabled: false }); expect(await getDefaultAdminEmail(config)).to.be(null); @@ -43,7 +39,7 @@ describe('getSettingsCollector / getDefaultAdminEmail', () => { }); }); - describe('xpack.monitoring.cluster_alerts.email_notifications.enabled = true', () => { + describe('monitoring.cluster_alerts.email_notifications.enabled = true', () => { it('returns value when email is defined', async () => { const config = setup({ adminEmail: 'hello@world' }); expect(await getDefaultAdminEmail(config)).to.be('hello@world'); diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js index d0e1d32a2baa4c..f51e7d22a0c7cf 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js @@ -11,11 +11,11 @@ import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY, KIBANA_SETTINGS_TYPE } from '../../. * If so, get email from kibana.yml */ export async function getDefaultAdminEmail(config) { - if (!config.get('xpack.monitoring.cluster_alerts.email_notifications.enabled')) { + if (!config.get('monitoring.cluster_alerts.email_notifications.enabled')) { return null; } - const emailAddressConfigKey = `xpack.monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`; + const emailAddressConfigKey = `monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`; const configuredEmailAddress = config.get(emailAddressConfigKey); return configuredEmailAddress || null; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js index d58f6f3254c762..699a364433b3e8 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js @@ -17,7 +17,7 @@ export function opsBuffer({ config, log, getOSInfo }) { // determine the cloud service in the background const cloudDetector = new CloudDetector(); - if (config.get('xpack.monitoring.tests.cloud_detector.enabled')) { + if (config.get('monitoring.tests.cloud_detector.enabled')) { cloudDetector.detectCloudService(); } diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js index bf79ddc2109029..3c02e2be58dec3 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js +++ b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js @@ -16,7 +16,7 @@ import { BulkUploader } from './bulk_uploader'; * @param {Object} server HapiJS server instance */ export function initBulkUploader({ config, ...params }) { - const interval = config.get('xpack.monitoring.kibana.collection.interval'); + const interval = config.get('monitoring.kibana.collection.interval'); return new BulkUploader({ interval, config, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js b/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js index 844dfc96bb19b9..2d310962238fd4 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js @@ -17,7 +17,7 @@ describe('ccs_utils', () => { const get = sinon.stub(); const config = { get }; - get.withArgs('xpack.monitoring.ccs.enabled').returns(false); + get.withArgs('monitoring.ui.ccs.enabled').returns(false); // falsy string values should be ignored const allPattern = prefixIndexPattern(config, indexPattern, '*'); @@ -32,7 +32,7 @@ describe('ccs_utils', () => { const get = sinon.stub(); const config = { get }; - get.withArgs('xpack.monitoring.ccs.enabled').returns(true); + get.withArgs('monitoring.ui.ccs.enabled').returns(true); // falsy string values should be ignored const undefinedPattern = prefixIndexPattern(config, indexPattern); @@ -49,7 +49,7 @@ describe('ccs_utils', () => { const get = sinon.stub(); const config = { get }; - get.withArgs('xpack.monitoring.ccs.enabled').returns(true); + get.withArgs('monitoring.ui.ccs.enabled').returns(true); const abcPattern = prefixIndexPattern(config, indexPattern, 'aBc'); const underscorePattern = prefixIndexPattern(config, indexPattern, 'cluster_one'); @@ -67,7 +67,7 @@ describe('ccs_utils', () => { const get = sinon.stub(); const config = { get }; - get.withArgs('xpack.monitoring.ccs.enabled').returns(true); + get.withArgs('monitoring.ui.ccs.enabled').returns(true); const pattern = prefixIndexPattern(config, indexPattern, '*'); diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js index ef8db59620f1a5..40070a6b0d0f24 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js @@ -84,7 +84,7 @@ export async function getApms(req, apmIndexPattern, clusterUuid) { const params = { index: apmIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), // FIXME + size: config.get('monitoring.ui.max_bucket_size'), // FIXME ignoreUnavailable: true, filterPath: [ // only filter path can filter for inner_hits diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js index 95ccb81f696be1..a24936dc0f8320 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js @@ -35,7 +35,7 @@ export function getApmsForClusters(req, apmIndexPattern, clusters) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); return Promise.all( clusters.map(async cluster => { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js index 54a0609d945de2..bfaec4f8a12949 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js @@ -28,7 +28,7 @@ export async function getStats(req, apmIndexPattern, clusterUuid) { const config = req.server.config(); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const params = { index: apmIndexPattern, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js index 5857ec32b22597..ef878e48925570 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js @@ -83,7 +83,7 @@ export async function getBeats(req, beatsIndexPattern, clusterUuid) { const params = { index: beatsIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), // FIXME + size: config.get('monitoring.ui.max_bucket_size'), // FIXME ignoreUnavailable: true, filterPath: [ // only filter path can filter for inner_hits diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js index 82a738755931d6..624abb894e5087 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js @@ -34,7 +34,7 @@ export function getBeatsForClusters(req, beatsIndexPattern, clusters) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); return Promise.all( clusters.map(async cluster => { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js index d326c84634e12d..1139489728dbfa 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js @@ -71,7 +71,7 @@ export function getLatestStats(req, beatsIndexPattern, clusterUuid) { uuids: { terms: { field: 'beats_stats.beat.uuid', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js index 80851a8498c263..0f90750a293fb7 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js @@ -28,7 +28,7 @@ export async function getStats(req, beatsIndexPattern, clusterUuid) { const config = req.server.config(); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const params = { index: beatsIndexPattern, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js b/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js index 5b3980d9619a8a..3409462156a077 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js @@ -16,7 +16,7 @@ * @return {String} The index pattern with the {@code cluster} prefix appropriately prepended. */ export function prefixIndexPattern(config, indexPattern, ccs) { - const ccsEnabled = config.get('xpack.monitoring.ccs.enabled'); + const ccsEnabled = config.get('monitoring.ui.ccs.enabled'); if (!ccsEnabled || !ccs) { return indexPattern; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js b/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js index d3456eeb2fe4e4..2b080a5c333fcf 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js @@ -55,7 +55,7 @@ export async function getClustersFromRequest( } = indexPatterns; const config = req.server.config(); - const size = config.get('xpack.monitoring.max_bucket_size'); + const size = config.get('monitoring.ui.max_bucket_size'); const isStandaloneCluster = clusterUuid === STANDALONE_CLUSTER_CLUSTER_UUID; let clusters = []; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js b/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js index c323cb381aaf24..54dc58a374c2c8 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js @@ -46,7 +46,7 @@ function fetchClusterStats(req, esIndexPattern, clusterUuid) { const metric = ElasticsearchMetric.getMetricFields(); const params = { index: esIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, filterPath: [ 'hits.hits._index', diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js b/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js index b7c387e74ec968..fbe6c8ec4cfa3e 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js @@ -20,7 +20,7 @@ function getMockReq(metricsBuckets = []) { get: sinon.stub(), }; - config.get.withArgs('xpack.monitoring.min_interval_seconds').returns(10); + config.get.withArgs('monitoring.ui.min_interval_seconds').returns(10); return { server: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js b/x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js index 798a94abbe4849..0c4736e91ea109 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js @@ -28,7 +28,7 @@ export async function getMetrics( // TODO: Pass in req parameters as explicit function parameters let min = moment.utc(req.payload.timeRange.min).valueOf(); const max = moment.utc(req.payload.timeRange.max).valueOf(); - const minIntervalSeconds = config.get('xpack.monitoring.min_interval_seconds'); + const minIntervalSeconds = config.get('monitoring.ui.min_interval_seconds'); const bucketSize = calculateTimeseriesInterval(min, max, minIntervalSeconds); const timezone = await getTimezone(req); diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js index 658ee96c1f0841..8aef402f881e81 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js @@ -23,7 +23,7 @@ export function getMlJobs(req, esIndexPattern) { checkParam(esIndexPattern, 'esIndexPattern in getMlJobs'); const config = req.server.config(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const start = req.payload.timeRange.min; // no wrapping in moment :) const end = req.payload.timeRange.max; const clusterUuid = req.params.clusterUuid; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js index 6fe8ccfd890432..938a9b9d55e439 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js @@ -97,7 +97,7 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false, shard const params = { index: esIndexPattern, // TODO: composite aggregation - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, filterPath: [ // only filter path can filter for inner_hits diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js index 7581a325909712..c248ad743e0ec8 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js @@ -44,7 +44,7 @@ export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, n const min = start; const bucketSize = Math.max( - config.get('xpack.monitoring.min_interval_seconds'), + config.get('monitoring.ui.min_interval_seconds'), calculateAuto(100, duration).asSeconds() ); @@ -59,7 +59,7 @@ export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, n const params = { index: esIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, body: { query: createQuery({ @@ -78,7 +78,7 @@ export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, n terms: { field: `source_node.uuid`, include: uuidsToInclude, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, aggs: { by_date: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js index 51c61046e9cda2..e18d328e8725bb 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js @@ -38,7 +38,7 @@ export async function getPaginatedNodes( { clusterStats, nodesShardCount } ) { const config = req.server.config(); - const size = config.get('xpack.monitoring.max_bucket_size'); + const size = config.get('monitoring.ui.max_bucket_size'); const nodes = await getNodeIds(req, esIndexPattern, { clusterUuid }, size); // Add `isOnline` and shards from the cluster state and shard stats @@ -63,7 +63,7 @@ export async function getPaginatedNodes( const groupBy = { field: `source_node.uuid`, include: nodes.map(node => node.uuid), - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }; const metricSeriesData = await getMetrics( req, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js index e8d484e7021f47..c77bcc4f62e611 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js @@ -12,7 +12,7 @@ import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; async function getUnassignedShardData(req, esIndexPattern, cluster) { const config = req.server.config(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const metric = ElasticsearchMetric.getMetricFields(); const params = { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js index c11bd4aead693f..7823884dc749d4 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js @@ -11,7 +11,7 @@ import { ElasticsearchMetric } from '../../metrics'; async function getShardCountPerNode(req, esIndexPattern, cluster) { const config = req.server.config(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const metric = ElasticsearchMetric.getMetricFields(); const params = { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js index 3be5650b7d3bc6..40412c03b0ef9d 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js @@ -55,7 +55,7 @@ export function getShardAllocation( const metric = ElasticsearchMetric.getMetricFields(); const params = { index: esIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, body: { query: createQuery({ type: 'shards', clusterUuid, metric, filters }), diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js index eddd50612cdb13..8c4834e5d5e406 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js @@ -9,7 +9,7 @@ * @param {Boolean} includeNodes - whether to add the aggs for node shards */ export function getShardAggs(config, includeNodes, includeIndices) { - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const aggSize = 10; const indicesAgg = { terms: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js b/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js index af6563bae682d5..c272c38f00d552 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js @@ -31,7 +31,7 @@ export function getKibanas(req, kbnIndexPattern, { clusterUuid }) { const params = { index: kbnIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, body: { query: createQuery({ diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js b/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js index dbf1c41dcf4e54..e50e8bda3c907b 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js @@ -49,7 +49,7 @@ export function getKibanasForClusters(req, kbnIndexPattern, clusters) { kibana_uuids: { terms: { field: 'kibana_stats.kibana.uuid', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, aggs: { latest_report: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js index 7a20d7737c5e89..b876e3ba05d703 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js @@ -70,7 +70,7 @@ export async function getLogs( const params = { index: filebeatIndexPattern, - size: Math.min(50, config.get('xpack.monitoring.elasticsearch.logFetchCount')), + size: Math.min(50, config.get('monitoring.ui.elasticsearch.logFetchCount')), filterPath: [ 'hits.hits._source.message', 'hits.hits._source.log.level', diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js index d0de2c3f5df3a1..55baa3cf10b508 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js @@ -60,7 +60,7 @@ export function getLogstashForClusters(req, lsIndexPattern, clusters) { logstash_uuids: { terms: { field: 'logstash_stats.logstash.uuid', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, aggs: { latest_report: { @@ -119,7 +119,7 @@ export function getLogstashForClusters(req, lsIndexPattern, clusters) { logstash_versions: { terms: { field: 'logstash_stats.logstash.version', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, }, pipelines_nested: { @@ -135,7 +135,7 @@ export function getLogstashForClusters(req, lsIndexPattern, clusters) { queue_types: { terms: { field: 'logstash_stats.pipelines.queue.type', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, aggs: { num_pipelines: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js index 93b70d7b79f0a1..06696abdb031f0 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js @@ -31,7 +31,7 @@ export function getNodes(req, lsIndexPattern, { clusterUuid }) { const params = { index: lsIndexPattern, - size: config.get('xpack.monitoring.max_bucket_size'), // FIXME + size: config.get('monitoring.ui.max_bucket_size'), // FIXME ignoreUnavailable: true, body: { query: createQuery({ diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js index ef9ef90e8f3108..ffc7e9ce1d6c28 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js @@ -37,7 +37,7 @@ export async function getPaginatedPipelines( queryText ) { const config = req.server.config(); - const size = config.get('xpack.monitoring.max_bucket_size'); + const size = config.get('monitoring.ui.max_bucket_size'); const pipelines = await getLogstashPipelineIds( req, lsIndexPattern, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js index eeeffd74e91f76..35a4295de298bf 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js @@ -111,7 +111,7 @@ export async function getPipeline(req, config, lsIndexPattern, clusterUuid, pipe }; // Determine metrics' timeseries interval based on version's timespan - const minIntervalSeconds = config.get('xpack.monitoring.min_interval_seconds'); + const minIntervalSeconds = config.get('monitoring.ui.min_interval_seconds'); const timeseriesInterval = calculateTimeseriesInterval( version.firstSeen, version.lastSeen, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js index 1858674a01b86e..d9c03819b0098b 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js @@ -171,7 +171,7 @@ export function getPipelineStatsAggregation( logstashIndexPattern, pipelineId, version, - config.get('xpack.monitoring.max_bucket_size'), + config.get('monitoring.ui.max_bucket_size'), callWithRequest, req ); diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js index 7dfa8d4a163ce9..7521389c379eae 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js @@ -37,7 +37,7 @@ function fetchPipelineVersions(...args) { by_pipeline_hash: { terms: { field: 'logstash_stats.pipelines.hash', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), order: { 'path_to_root>first_seen': 'desc' }, }, aggs: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js index 49c2dff2d6080a..134dd88b36ce64 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js @@ -130,7 +130,7 @@ export async function getPipelineVertex( }; // Determine metrics' timeseries interval based on version's timespan - const minIntervalSeconds = config.get('xpack.monitoring.min_interval_seconds'); + const minIntervalSeconds = config.get('monitoring.ui.min_interval_seconds'); const timeseriesInterval = calculateTimeseriesInterval( version.firstSeen, version.lastSeen, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js index c91182188b213e..425ca5731926c6 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js @@ -216,7 +216,7 @@ export function getPipelineVertexStatsAggregation( version, vertexId, timeSeriesIntervalInSeconds, - config.get('xpack.monitoring.max_bucket_size'), + config.get('monitoring.ui.max_bucket_size'), callWithRequest, req ); diff --git a/x-pack/legacy/plugins/monitoring/server/plugin.js b/x-pack/legacy/plugins/monitoring/server/plugin.js index 163bc43945be1c..ef346e95ad0757 100644 --- a/x-pack/legacy/plugins/monitoring/server/plugin.js +++ b/x-pack/legacy/plugins/monitoring/server/plugin.js @@ -48,7 +48,7 @@ export class Plugin { /* * End-user-facing services */ - const uiEnabled = config.get('xpack.monitoring.ui.enabled'); + const uiEnabled = config.get('monitoring.ui.enabled'); if (uiEnabled) { await instantiateClient({ @@ -98,7 +98,7 @@ export class Plugin { kbnServerStatus: kbnServer.status, kbnServerVersion: kbnServer.version, }); - const kibanaCollectionEnabled = config.get('xpack.monitoring.kibana.collection.enabled'); + const kibanaCollectionEnabled = config.get('monitoring.kibana.collection.enabled'); if (kibanaCollectionEnabled) { /* @@ -125,14 +125,12 @@ export class Plugin { core.injectUiAppVars('monitoring', () => { const config = core.config(); return { - maxBucketSize: config.get('xpack.monitoring.max_bucket_size'), - minIntervalSeconds: config.get('xpack.monitoring.min_interval_seconds'), + maxBucketSize: config.get('monitoring.ui.max_bucket_size'), + minIntervalSeconds: config.get('monitoring.ui.min_interval_seconds'), kbnIndex: config.get('kibana.index'), - showLicenseExpiration: config.get('xpack.monitoring.show_license_expiration'), - showCgroupMetricsElasticsearch: config.get( - 'xpack.monitoring.ui.container.elasticsearch.enabled' - ), - showCgroupMetricsLogstash: config.get('xpack.monitoring.ui.container.logstash.enabled'), // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 + showLicenseExpiration: config.get('monitoring.ui.show_license_expiration'), + showCgroupMetricsElasticsearch: config.get('monitoring.ui.container.elasticsearch.enabled'), + showCgroupMetricsLogstash: config.get('monitoring.ui.container.logstash.enabled'), // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 }; }); } diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js index 2d4bded9fc4c85..fcdf4ad8a706c0 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js @@ -26,7 +26,7 @@ function getBucketScript(max, min) { function buildRequest(req, config, esIndexPattern) { const min = moment.utc(req.payload.timeRange.min).valueOf(); const max = moment.utc(req.payload.timeRange.max).valueOf(); - const maxBucketSize = config.get('xpack.monitoring.max_bucket_size'); + const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const aggs = { ops_synced_max: { max: { diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js index 10226d74ed0010..25ead723e3ddb8 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js @@ -61,7 +61,7 @@ export function esNodeRoute(server) { metricSet = metricSetOverview; // set the cgroup option if needed const showCgroupMetricsElasticsearch = config.get( - 'xpack.monitoring.ui.container.elasticsearch.enabled' + 'monitoring.ui.container.elasticsearch.enabled' ); const metricCpu = metricSet.find(m => m.name === 'node_cpu_metric'); if (showCgroupMetricsElasticsearch) { diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js index d5ce9d1686f8a8..bd3ae5f5c2679b 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js @@ -60,9 +60,7 @@ export function logstashNodeRoute(server) { } else { metricSet = metricSetOverview; // set the cgroup option if needed - const showCgroupMetricsLogstash = config.get( - 'xpack.monitoring.ui.container.logstash.enabled' - ); + const showCgroupMetricsLogstash = config.get('monitoring.ui.container.logstash.enabled'); const metricCpu = metricSet.find(m => m.name === 'logstash_node_cpu_metric'); if (showCgroupMetricsLogstash) { metricCpu.keys = ['logstash_node_cgroup_quota_as_cpu_utilization']; diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js index c5fd76487cca1d..93330880babcc7 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js @@ -36,7 +36,7 @@ export function logstashClusterPipelineIdsRoute(server) { const { ccs } = req.payload; const clusterUuid = req.params.clusterUuid; const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); - const size = config.get('xpack.monitoring.max_bucket_size'); + const size = config.get('monitoring.ui.max_bucket_size'); try { const pipelines = await getLogstashPipelineIds(req, lsIndexPattern, { clusterUuid }, size); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts index fc85cbe442ddff..4738ab5b8af83f 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts @@ -40,7 +40,7 @@ export function fetchClusterUuids({ server, callCluster, start, end }: StatsColl cluster_uuids: { terms: { field: 'cluster_uuid', - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), }, }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js index 8e5a59361e52f7..52d34258b5fa4d 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.js @@ -31,7 +31,7 @@ export function fetchElasticsearchStats(server, callCluster, clusterUuids) { const config = server.config(); const params = { index: INDEX_PATTERN_ELASTICSEARCH, - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), ignoreUnavailable: true, filterPath: [ 'hits.hits._source.cluster_uuid', diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js index 2632a8f6e041df..b87f632308e4d6 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.js @@ -217,7 +217,7 @@ export async function fetchHighLevelStats(server, callCluster, clusterUuids, sta const params = { index: getIndexPatternForStackProduct(product), - size: config.get('xpack.monitoring.max_bucket_size'), + size: config.get('monitoring.ui.max_bucket_size'), headers: { 'X-QUERY-SOURCE': TELEMETRY_QUERY_SOURCE, }, diff --git a/x-pack/legacy/plugins/monitoring/ui_exports.js b/x-pack/legacy/plugins/monitoring/ui_exports.js index 2b5ea21a2bb452..9251deb673bd11 100644 --- a/x-pack/legacy/plugins/monitoring/ui_exports.js +++ b/x-pack/legacy/plugins/monitoring/ui_exports.js @@ -32,7 +32,7 @@ export const getUiExports = () => ({ injectDefaultVars(server) { const config = server.config(); return { - monitoringUiEnabled: config.get('xpack.monitoring.ui.enabled'), + monitoringUiEnabled: config.get('monitoring.ui.enabled'), }; }, hacks: ['plugins/monitoring/hacks/toggle_app_link_in_nav'], From 877985ca92db9990a55c1e8591abee1fbaf25e24 Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Thu, 30 Jan 2020 11:15:01 -0500 Subject: [PATCH 19/69] Import appropriate files to setup plugin system at the correct time (#55956) Co-authored-by: Elastic Machine --- x-pack/legacy/plugins/canvas/public/legacy_start.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/legacy/plugins/canvas/public/legacy_start.ts b/x-pack/legacy/plugins/canvas/public/legacy_start.ts index 972427e166afcd..21bf5aaa6d8184 100644 --- a/x-pack/legacy/plugins/canvas/public/legacy_start.ts +++ b/x-pack/legacy/plugins/canvas/public/legacy_start.ts @@ -16,6 +16,12 @@ import 'uiExports/spyModes'; import 'uiExports/embeddableFactories'; import 'uiExports/interpreter'; +// TODO: These dependencies should be moved into plugin startup methods +// Load the interpreter so that the kbnInterpreter global will be available when plugins load +import 'plugins/interpreter/interpreter'; +// Load our app component to initialize registries +import './components/app'; + // load application code import 'uiExports/canvas'; From 349851ca7be822a9d88419011df0515548f1b0a2 Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Thu, 30 Jan 2020 11:15:46 -0500 Subject: [PATCH 20/69] Only fire appState changes when there is a change (#56183) Co-authored-by: Elastic Machine --- .../canvas/public/components/router/index.js | 23 ------- .../canvas/public/components/router/index.ts | 63 +++++++++++++++++++ .../plugins/canvas/public/lib/app_state.ts | 11 +++- 3 files changed, 71 insertions(+), 26 deletions(-) delete mode 100644 x-pack/legacy/plugins/canvas/public/components/router/index.js create mode 100644 x-pack/legacy/plugins/canvas/public/components/router/index.ts diff --git a/x-pack/legacy/plugins/canvas/public/components/router/index.js b/x-pack/legacy/plugins/canvas/public/components/router/index.js deleted file mode 100644 index 430d6a53436624..00000000000000 --- a/x-pack/legacy/plugins/canvas/public/components/router/index.js +++ /dev/null @@ -1,23 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { connect } from 'react-redux'; -import { setFullscreen } from '../../state/actions/transient'; -import { - enableAutoplay, - setRefreshInterval, - setAutoplayInterval, -} from '../../state/actions/workpad'; -import { Router as Component } from './router'; - -const mapDispatchToState = { - enableAutoplay, - setAutoplayInterval, - setFullscreen, - setRefreshInterval, -}; - -export const Router = connect(null, mapDispatchToState)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/router/index.ts b/x-pack/legacy/plugins/canvas/public/components/router/index.ts new file mode 100644 index 00000000000000..5e014870f5158a --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/router/index.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { connect } from 'react-redux'; +// @ts-ignore untyped local +import { setFullscreen } from '../../state/actions/transient'; +import { + enableAutoplay, + setRefreshInterval, + setAutoplayInterval, + // @ts-ignore untyped local +} from '../../state/actions/workpad'; +// @ts-ignore untyped local +import { Router as Component } from './router'; +import { State } from '../../../types'; + +const mapDispatchToProps = { + enableAutoplay, + setAutoplayInterval, + setFullscreen, + setRefreshInterval, +}; + +const mapStateToProps = (state: State) => ({ + refreshInterval: state.transient.refresh.interval, + autoplayInterval: state.transient.autoplay.interval, + autoplay: state.transient.autoplay.enabled, + fullscreen: state.transient.fullScreen, +}); + +export const Router = connect( + mapStateToProps, + mapDispatchToProps, + (stateProps, dispatchProps, ownProps) => { + return { + ...ownProps, + ...dispatchProps, + setRefreshInterval: (interval: number) => { + if (interval !== stateProps.refreshInterval) { + dispatchProps.setRefreshInterval(interval); + } + }, + setAutoplayInterval: (interval: number) => { + if (interval !== stateProps.autoplayInterval) { + dispatchProps.setRefreshInterval(interval); + } + }, + enableAutoplay: (autoplay: boolean) => { + if (autoplay !== stateProps.autoplay) { + dispatchProps.enableAutoplay(autoplay); + } + }, + setFullscreen: (fullscreen: boolean) => { + if (fullscreen !== stateProps.fullscreen) { + dispatchProps.setFullscreen(fullscreen); + } + }, + }; + } +)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/lib/app_state.ts b/x-pack/legacy/plugins/canvas/public/lib/app_state.ts index 955125b7131400..c93e505c595fd0 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/app_state.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/app_state.ts @@ -13,7 +13,7 @@ import { getWindow } from './get_window'; import { historyProvider } from './history_provider'; // @ts-ignore untyped local import { routerProvider } from './router_provider'; -import { createTimeInterval, isValidTimeInterval } from './time_interval'; +import { createTimeInterval, isValidTimeInterval, getTimeInterval } from './time_interval'; import { AppState, AppStateKeys } from '../../types'; export function getDefaultAppState(): AppState { @@ -112,7 +112,12 @@ export function setRefreshInterval(payload: string) { const appValue = appState[AppStateKeys.REFRESH_INTERVAL]; if (payload !== appValue) { - appState[AppStateKeys.REFRESH_INTERVAL] = payload; - routerProvider().updateAppState(appState); + if (getTimeInterval(payload)) { + appState[AppStateKeys.REFRESH_INTERVAL] = payload; + routerProvider().updateAppState(appState); + } else { + delete appState[AppStateKeys.REFRESH_INTERVAL]; + routerProvider().updateAppState(appState); + } } } From 8a4d68092b90c271262b524d7c7a8ffbcce3ffc4 Mon Sep 17 00:00:00 2001 From: Brittany Joiner Date: Thu, 30 Jan 2020 11:59:14 -0500 Subject: [PATCH 21/69] Sync badge (#55113) * adding span sync badge on waterfall and flyout --- .../Waterfall/SpanFlyout/index.tsx | 2 + .../Waterfall/SyncBadge.stories.tsx | 44 ++++++++++++++++++ .../Waterfall/SyncBadge.tsx | 46 +++++++++++++++++++ .../Waterfall/WaterfallItem.tsx | 2 + 4 files changed, 94 insertions(+) create mode 100644 x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx create mode 100644 x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx index 4863d6519de070..6f93762e11a82c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx @@ -34,6 +34,7 @@ import { DatabaseContext } from './DatabaseContext'; import { StickySpanProperties } from './StickySpanProperties'; import { HttpInfoSummaryItem } from '../../../../../../shared/Summary/HttpInfoSummaryItem'; import { SpanMetadata } from '../../../../../../shared/MetadataTable/SpanMetadata'; +import { SyncBadge } from '../SyncBadge'; function formatType(type: string) { switch (type) { @@ -188,6 +189,7 @@ export function SpanFlyout({ {spanTypes.spanAction} )} + ]} /> diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx new file mode 100644 index 00000000000000..c7d3f6cc6f0c6e --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { SyncBadge } from './SyncBadge'; + +storiesOf('app/TransactionDetails/SyncBadge', module) + .add( + 'sync=true', + () => { + return ; + }, + { + info: { + source: false + } + } + ) + .add( + 'sync=false', + () => { + return ; + }, + { + info: { + source: false + } + } + ) + .add( + 'sync=undefined', + () => { + return ; + }, + { + info: { + source: false + } + } + ); diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx new file mode 100644 index 00000000000000..764f15f943ad2b --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import styled from 'styled-components'; +import { px, units } from '../../../../../../style/variables'; + +const SpanBadge = styled(EuiBadge)` + display: inline-block; + margin-right: ${px(units.quarter)}; +`; + +interface SyncBadgeProps { + /** + * Is the request synchronous? True will show blocking, false will show async. + */ + sync?: boolean; +} + +export function SyncBadge({ sync }: SyncBadgeProps) { + switch (sync) { + case true: + return ( + + {i18n.translate('xpack.apm.transactionDetails.syncBadgeBlocking', { + defaultMessage: 'blocking' + })} + + ); + case false: + return ( + + {i18n.translate('xpack.apm.transactionDetails.syncBadgeAsync', { + defaultMessage: 'async' + })} + + ); + default: + return null; + } +} diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx index 8a82547d717db2..f57ccc3c344679 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx @@ -17,6 +17,7 @@ import { ErrorCount } from '../../ErrorCount'; import { IWaterfallItem } from './waterfall_helpers/waterfall_helpers'; import { ErrorOverviewLink } from '../../../../../shared/Links/apm/ErrorOverviewLink'; import { TRACE_ID } from '../../../../../../../common/elasticsearch_fieldnames'; +import { SyncBadge } from './SyncBadge'; type ItemType = 'transaction' | 'span' | 'error'; @@ -231,6 +232,7 @@ export function WaterfallItem({ ) : null} + {item.docType === 'span' && } ); From b7bcff71deab515331c5b6223f75d67196b9f60a Mon Sep 17 00:00:00 2001 From: Jimmy Kuang Date: Thu, 30 Jan 2020 10:30:14 -0800 Subject: [PATCH 22/69] System index templates can't be edited (#55229) * Removed period validation * Add back period validation * Fix EsLint * Undo Snapshot changes from Index Management bug * Undo Capitalization Co-authored-by: Elastic Machine --- .../template_form/steps/step_logistics.tsx | 3 +- .../template_form/template_form_schemas.tsx | 124 +++++++++--------- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/public/app/components/template_form/steps/step_logistics.tsx b/x-pack/legacy/plugins/index_management/public/app/components/template_form/steps/step_logistics.tsx index 290ade35045512..d2134837c15e52 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/template_form/steps/step_logistics.tsx +++ b/x-pack/legacy/plugins/index_management/public/app/components/template_form/steps/step_logistics.tsx @@ -18,7 +18,7 @@ import { } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/components'; import { documentationService } from '../../../services/documentation'; import { StepProps } from '../types'; -import { schemas } from '../template_form_schemas'; +import { schemas, nameConfig, nameConfigWithoutValidations } from '../template_form_schemas'; // Create or Form components with partial props that are common to all instances const UseField = getUseField({ component: Field }); @@ -131,6 +131,7 @@ export const StepLogistics: React.FunctionComponent = ({ ['data-test-subj']: name.testSubject, euiFieldProps: { disabled: isEditing }, }} + config={isEditing ? nameConfigWithoutValidations : nameConfig} /> {/* Index patterns */} diff --git a/x-pack/legacy/plugins/index_management/public/app/components/template_form/template_form_schemas.tsx b/x-pack/legacy/plugins/index_management/public/app/components/template_form/template_form_schemas.tsx index 5f3e28ddffb8ef..ed2616cc64e381 100644 --- a/x-pack/legacy/plugins/index_management/public/app/components/template_form/template_form_schemas.tsx +++ b/x-pack/legacy/plugins/index_management/public/app/components/template_form/template_form_schemas.tsx @@ -12,6 +12,7 @@ import { FormSchema, FIELD_TYPES, VALIDATION_TYPES, + FieldConfig, } from '../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; import { @@ -34,70 +35,71 @@ const { const { toInt } = fieldFormatters; const indexPatternInvalidCharacters = INVALID_INDEX_PATTERN_CHARS.join(' '); -export const schemas: Record = { - logistics: { - name: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.fieldNameLabel', { - defaultMessage: 'Name', +export const nameConfig: FieldConfig = { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.fieldNameLabel', { + defaultMessage: 'Name', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.idxMgmt.templateValidation.templateNameRequiredError', { + defaultMessage: 'A template name is required.', + }) + ), + }, + { + validator: containsCharsField({ + chars: ' ', + message: i18n.translate('xpack.idxMgmt.templateValidation.templateNameSpacesError', { + defaultMessage: 'Spaces are not allowed in a template name.', + }), }), - validations: [ - { - validator: emptyField( - i18n.translate('xpack.idxMgmt.templateValidation.templateNameRequiredError', { - defaultMessage: 'A template name is required.', - }) - ), - }, - { - validator: containsCharsField({ - chars: ' ', - message: i18n.translate('xpack.idxMgmt.templateValidation.templateNameSpacesError', { - defaultMessage: 'Spaces are not allowed in a template name.', - }), - }), - }, - { - validator: startsWithField({ - char: '_', - message: i18n.translate( - 'xpack.idxMgmt.templateValidation.templateNameUnderscoreError', - { - defaultMessage: 'A template name must not start with an underscore.', - } - ), - }), - }, - { - validator: startsWithField({ - char: '.', - message: i18n.translate('xpack.idxMgmt.templateValidation.templateNamePeriodError', { - defaultMessage: 'A template name must not start with a period.', - }), - }), - }, - { - validator: containsCharsField({ - chars: INVALID_TEMPLATE_NAME_CHARS, - message: ({ charsFound }) => - i18n.translate( - 'xpack.idxMgmt.templateValidation.templateNameInvalidaCharacterError', - { - defaultMessage: 'A template name must not contain the character "{invalidChar}"', - values: { invalidChar: charsFound[0] }, - } - ), + }, + { + validator: startsWithField({ + char: '_', + message: i18n.translate('xpack.idxMgmt.templateValidation.templateNameUnderscoreError', { + defaultMessage: 'A template name must not start with an underscore.', + }), + }), + }, + { + validator: startsWithField({ + char: '.', + message: i18n.translate('xpack.idxMgmt.templateValidation.templateNamePeriodError', { + defaultMessage: 'A template name must not start with a period.', + }), + }), + }, + { + validator: containsCharsField({ + chars: INVALID_TEMPLATE_NAME_CHARS, + message: ({ charsFound }) => + i18n.translate('xpack.idxMgmt.templateValidation.templateNameInvalidaCharacterError', { + defaultMessage: 'A template name must not contain the character "{invalidChar}"', + values: { invalidChar: charsFound[0] }, }), - }, - { - validator: lowerCaseStringField( - i18n.translate('xpack.idxMgmt.templateValidation.templateNameLowerCaseRequiredError', { - defaultMessage: 'The template name must be in lowercase.', - }) - ), - }, - ], + }), }, + { + validator: lowerCaseStringField( + i18n.translate('xpack.idxMgmt.templateValidation.templateNameLowerCaseRequiredError', { + defaultMessage: 'The template name must be in lowercase.', + }) + ), + }, + ], +}; + +export const nameConfigWithoutValidations: FieldConfig = { + ...nameConfig, + validations: [], +}; + +export const schemas: Record = { + logistics: { + name: nameConfig, indexPatterns: { type: FIELD_TYPES.COMBO_BOX, defaultValue: [], From 2b53c74cd9c1889b84a817b7a2817a839a9b5adf Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 30 Jan 2020 19:03:14 +0000 Subject: [PATCH 23/69] chore(NA): delete data/optimize with kbn clean (#55890) Co-authored-by: Elastic Machine --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9707d3863d295d..425527a058e862 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "clean": { "extraPatterns": [ "build", - "optimize", + "data/optimize", "built_assets", ".eslintcache", ".node_binaries" From 8398a1c77cde0e190126ff13804d182fda96e74d Mon Sep 17 00:00:00 2001 From: Dan Panzarella Date: Thu, 30 Jan 2020 14:25:56 -0500 Subject: [PATCH 24/69] [Endpoint] Add Endpoint Details route (#55746) * Add Endpoint Details route * add Endpoint Details tests * sacrifices to the Type gods * update to latest endpoint schema Co-authored-by: Elastic Machine --- .../endpoint/server/routes/endpoints.test.ts | 78 +++++++++++++++++++ .../endpoint/server/routes/endpoints.ts | 32 +++++++- .../endpoint/endpoint_query_builders.test.ts | 32 +++++++- .../endpoint/endpoint_query_builders.ts | 24 ++++++ 4 files changed, 162 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/endpoint/server/routes/endpoints.test.ts b/x-pack/plugins/endpoint/server/routes/endpoints.test.ts index 04a38972401ed9..be14554f128c3c 100644 --- a/x-pack/plugins/endpoint/server/routes/endpoints.test.ts +++ b/x-pack/plugins/endpoint/server/routes/endpoints.test.ts @@ -120,4 +120,82 @@ describe('test endpoint route', () => { expect(endpointResultList.request_page_index).toEqual(10); expect(endpointResultList.request_page_size).toEqual(10); }); + + describe('Endpoint Details route', () => { + it('should return 404 on no results', async () => { + const mockRequest = httpServerMock.createKibanaRequest({ params: { id: 'BADID' } }); + mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => + Promise.resolve({ + took: 3, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: { + value: 9, + relation: 'eq', + }, + max_score: null, + hits: [], + }, + }) + ); + [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + path.startsWith('/api/endpoint/endpoints') + )!; + + await routeHandler( + ({ + core: { + elasticsearch: { + dataClient: mockScopedClient, + }, + }, + } as unknown) as RequestHandlerContext, + mockRequest, + mockResponse + ); + + expect(mockScopedClient.callAsCurrentUser).toBeCalled(); + expect(routeConfig.options).toEqual({ authRequired: true }); + expect(mockResponse.notFound).toBeCalled(); + const message = mockResponse.notFound.mock.calls[0][0]?.body; + expect(message).toEqual('Endpoint Not Found'); + }); + + it('should return a single endpoint', async () => { + const mockRequest = httpServerMock.createKibanaRequest({ + params: { id: (data as any).hits.hits[0]._id }, + }); + const response: SearchResponse = (data as unknown) as SearchResponse< + EndpointMetadata + >; + mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); + [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + path.startsWith('/api/endpoint/endpoints') + )!; + + await routeHandler( + ({ + core: { + elasticsearch: { + dataClient: mockScopedClient, + }, + }, + } as unknown) as RequestHandlerContext, + mockRequest, + mockResponse + ); + + expect(mockScopedClient.callAsCurrentUser).toBeCalled(); + expect(routeConfig.options).toEqual({ authRequired: true }); + expect(mockResponse.ok).toBeCalled(); + const result = mockResponse.ok.mock.calls[0][0]?.body as EndpointMetadata; + expect(result).toHaveProperty('endpoint'); + }); + }); }); diff --git a/x-pack/plugins/endpoint/server/routes/endpoints.ts b/x-pack/plugins/endpoint/server/routes/endpoints.ts index 4fc3e653f94265..24ad8e3941f5e1 100644 --- a/x-pack/plugins/endpoint/server/routes/endpoints.ts +++ b/x-pack/plugins/endpoint/server/routes/endpoints.ts @@ -8,7 +8,10 @@ import { IRouter } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { schema } from '@kbn/config-schema'; -import { kibanaRequestToEndpointListQuery } from '../services/endpoint/endpoint_query_builders'; +import { + kibanaRequestToEndpointListQuery, + kibanaRequestToEndpointFetchQuery, +} from '../services/endpoint/endpoint_query_builders'; import { EndpointMetadata, EndpointResultList } from '../../common/types'; import { EndpointAppContext } from '../types'; @@ -51,6 +54,33 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp } } ); + + router.get( + { + path: '/api/endpoint/endpoints/{id}', + validate: { + params: schema.object({ id: schema.string() }), + }, + options: { authRequired: true }, + }, + async (context, req, res) => { + try { + const query = kibanaRequestToEndpointFetchQuery(req, endpointAppContext); + const response = (await context.core.elasticsearch.dataClient.callAsCurrentUser( + 'search', + query + )) as SearchResponse; + + if (response.hits.hits.length === 0) { + return res.notFound({ body: 'Endpoint Not Found' }); + } + + return res.ok({ body: response.hits.hits[0]._source }); + } catch (err) { + return res.internalError({ body: err }); + } + } + ); } function mapToEndpointResultList( diff --git a/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.test.ts b/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.test.ts index 3c931a251d6977..e453f777fbd502 100644 --- a/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.test.ts +++ b/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.test.ts @@ -5,10 +5,13 @@ */ import { httpServerMock, loggingServiceMock } from '../../../../../../src/core/server/mocks'; import { EndpointConfigSchema } from '../../config'; -import { kibanaRequestToEndpointListQuery } from './endpoint_query_builders'; +import { + kibanaRequestToEndpointListQuery, + kibanaRequestToEndpointFetchQuery, +} from './endpoint_query_builders'; -describe('test query builder', () => { - describe('test query builder request processing', () => { +describe('query builder', () => { + describe('EndpointListQuery', () => { it('test default query params for all endpoints when no params or body is provided', async () => { const mockRequest = httpServerMock.createKibanaRequest({ body: {}, @@ -51,4 +54,27 @@ describe('test query builder', () => { } as Record); }); }); + + describe('EndpointFetchQuery', () => { + it('searches for the correct ID', () => { + const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; + const mockRequest = httpServerMock.createKibanaRequest({ + params: { + id: mockID, + }, + }); + const query = kibanaRequestToEndpointFetchQuery(mockRequest, { + logFactory: loggingServiceMock.create(), + config: () => Promise.resolve(EndpointConfigSchema.validate({})), + }); + expect(query).toEqual({ + body: { + query: { match: { 'host.id.keyword': mockID } }, + sort: [{ 'event.created': { order: 'desc' } }], + size: 1, + }, + index: 'endpoint-agent*', + }); + }); + }); }); diff --git a/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.ts b/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.ts index 102c268cf9ec4c..b4f295a64b6ea0 100644 --- a/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.ts +++ b/x-pack/plugins/endpoint/server/services/endpoint/endpoint_query_builders.ts @@ -65,3 +65,27 @@ async function getPagingProperties( pageIndex: pagingProperties.page_index || config.endpointResultListDefaultFirstPageIndex, }; } + +export const kibanaRequestToEndpointFetchQuery = ( + request: KibanaRequest, + endpointAppContext: EndpointAppContext +) => { + return { + body: { + query: { + match: { + 'host.id.keyword': request.params.id, + }, + }, + sort: [ + { + 'event.created': { + order: 'desc', + }, + }, + ], + size: 1, + }, + index: EndpointAppConstants.ENDPOINT_INDEX_NAME, + }; +}; From 642c694117ac3dcea33c6597a33b94cb276a75d4 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 30 Jan 2020 13:55:17 -0600 Subject: [PATCH 25/69] Add missing docker settings (#56411) Closes #54811 --- .../resources/bin/kibana-docker | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker index 7a82ca0b1609c0..34ba25f92beb6a 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker @@ -18,6 +18,11 @@ kibana_vars=( console.enabled console.proxyConfig console.proxyFilter + cpu.cgroup.path.override + cpuacct.cgroup.path.override + csp.rules + csp.strict + csp.warnLegacyBrowsers elasticsearch.customHeaders elasticsearch.hosts elasticsearch.logQueries @@ -30,6 +35,7 @@ kibana_vars=( elasticsearch.sniffInterval elasticsearch.sniffOnConnectionFault elasticsearch.sniffOnStart + elasticsearch.ssl.alwaysPresentCertificate elasticsearch.ssl.certificate elasticsearch.ssl.certificateAuthorities elasticsearch.ssl.key @@ -42,9 +48,13 @@ kibana_vars=( elasticsearch.startupTimeout elasticsearch.username i18n.locale + interpreter.enableInVisualize + kibana.autocompleteTerminateAfter + kibana.autocompleteTimeout kibana.defaultAppId kibana.index logging.dest + logging.json logging.quiet logging.rotate.enabled logging.rotate.everyBytes @@ -55,18 +65,32 @@ kibana_vars=( logging.useUTC logging.verbose map.includeElasticMapsService + map.proxyElasticMapsServiceInMaps + map.regionmap + map.tilemap.options.attribution + map.tilemap.options.maxZoom + map.tilemap.options.minZoom + map.tilemap.options.subdomains + map.tilemap.url + newsfeed.enabled ops.interval path.data pid.file regionmap server.basePath server.customResponseHeaders + server.compression.enabled + server.compression.referrerWhitelist + server.cors + server.cors.origin server.defaultRoute server.host + server.keepAliveTimeout server.maxPayloadBytes server.name server.port server.rewriteBasePath + server.socketTimeout server.ssl.cert server.ssl.certificate server.ssl.certificateAuthorities @@ -82,6 +106,7 @@ kibana_vars=( server.ssl.truststore.password server.ssl.redirectHttpFromPort server.ssl.supportedProtocols + server.xsrf.disableProtection server.xsrf.whitelist status.allowAnonymous status.v6ApiFormat @@ -96,11 +121,13 @@ kibana_vars=( xpack.apm.serviceMapEnabled xpack.apm.ui.enabled xpack.apm.ui.maxTraceItems + xpack.apm.ui.transactionGroupBucketSize apm_oss.apmAgentConfigurationIndex apm_oss.indexPattern apm_oss.errorIndices apm_oss.onboardingIndices apm_oss.spanIndices + apm_oss.sourcemapIndices apm_oss.transactionIndices apm_oss.metricsIndices xpack.canvas.enabled @@ -116,6 +143,8 @@ kibana_vars=( xpack.code.security.gitHostWhitelist xpack.code.security.gitProtocolWhitelist xpack.graph.enabled + xpack.graph.canEditDrillDownUrls + xpack.graph.savePolicy xpack.grokdebugger.enabled xpack.infra.enabled xpack.infra.query.partitionFactor @@ -128,11 +157,14 @@ kibana_vars=( xpack.infra.sources.default.fields.timestamp xpack.infra.sources.default.logAlias xpack.infra.sources.default.metricAlias + xpack.license_management.enabled xpack.ml.enabled + xpack.monitoring.cluster_alerts.email_notifications.email_address xpack.monitoring.elasticsearch.password xpack.monitoring.elasticsearch.pingTimeout xpack.monitoring.elasticsearch.hosts xpack.monitoring.elasticsearch.username + xpack.monitoring.elasticsearch.logFetchCount xpack.monitoring.elasticsearch.ssl.certificateAuthorities xpack.monitoring.elasticsearch.ssl.verificationMode xpack.monitoring.enabled @@ -166,6 +198,7 @@ kibana_vars=( xpack.reporting.csv.maxSizeBytes xpack.reporting.csv.scroll.duration xpack.reporting.csv.scroll.size + xpack.reporting.capture.maxAttempts xpack.reporting.enabled xpack.reporting.encryptionKey xpack.reporting.index @@ -183,6 +216,8 @@ kibana_vars=( xpack.reporting.queue.pollIntervalErrorMultiplier xpack.reporting.queue.timeout xpack.reporting.roles.allow + xpack.rollup.enabled + xpack.security.audit.enabled xpack.searchprofiler.enabled xpack.security.authc.providers xpack.security.authc.oidc.realm @@ -196,7 +231,10 @@ kibana_vars=( xpack.security.session.idleTimeout xpack.security.session.lifespan xpack.security.loginAssistanceMessage + telemetry.allowChangingOptInStatus telemetry.enabled + telemetry.optIn + telemetry.optInStatusUrl telemetry.sendUsageFrom ) From 89b3c428c21dfd6fb91d9245c7b095ebcffa3341 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 30 Jan 2020 21:03:03 +0100 Subject: [PATCH 26/69] [ML] Fix Data Visualizer responsive layout (#56372) * [ML] replace Example component with EuiListGroup * [ML] center alignment --- .../field_data_card/examples_list/example.tsx | 31 ------------------- .../examples_list/examples_list.tsx | 17 +++++++--- 2 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/example.tsx diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/example.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/example.tsx deleted file mode 100644 index 29fe690f4a43bb..00000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/example.tsx +++ /dev/null @@ -1,31 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { FC } from 'react'; - -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; - -interface Props { - example: string | object; -} - -export const Example: FC = ({ example }) => { - const exampleStr = typeof example === 'string' ? example : JSON.stringify(example); - - // Use 95% width for each example so that the truncation ellipses show up when - // wrapped inside a tooltip. - return ( - - - - - {exampleStr} - - - - - ); -}; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/examples_list.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/examples_list.tsx index 0bf911c1edf862..c8eb8101154017 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/examples_list.tsx +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/field_data_card/examples_list/examples_list.tsx @@ -6,12 +6,10 @@ import React, { FC } from 'react'; -import { EuiSpacer, EuiText } from '@elastic/eui'; +import { EuiListGroup, EuiListGroupItem, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Example } from './example'; - interface Props { examples: Array; } @@ -22,7 +20,14 @@ export const ExamplesList: FC = ({ examples }) => { } const examplesContent = examples.map((example, i) => { - return ; + return ( + + ); }); return ( @@ -39,7 +44,9 @@ export const ExamplesList: FC = ({ examples }) => { - {examplesContent} + + {examplesContent} +
    ); }; From 08e0cbc3ee90358148eafb2d14a2368004b76f15 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Thu, 30 Jan 2020 13:05:09 -0700 Subject: [PATCH 27/69] [skip-ci] Add example for migrating pre-handlers (#56080) --- src/core/MIGRATION_EXAMPLES.md | 137 +++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/src/core/MIGRATION_EXAMPLES.md b/src/core/MIGRATION_EXAMPLES.md index 568980f50117df..5517dfa7f9a23c 100644 --- a/src/core/MIGRATION_EXAMPLES.md +++ b/src/core/MIGRATION_EXAMPLES.md @@ -14,6 +14,7 @@ APIs to their New Platform equivalents. - [3. New Platform shim using New Platform router](#3-new-platform-shim-using-new-platform-router) - [4. New Platform plugin](#4-new-platform-plugin) - [Accessing Services](#accessing-services) + - [Migrating Hapi "pre" handlers](#migrating-hapi-pre-handlers) - [Chrome](#chrome) - [Updating an application navlink](#updating-application-navlink) - [Chromeless Applications](#chromeless-applications) @@ -450,6 +451,142 @@ class Plugin { } ``` +### Migrating Hapi "pre" handlers + +In the Legacy Platform, routes could provide a "pre" option in their config to +register a function that should be run prior to the route handler. These +"pre" handlers allow routes to share some business logic that may do some +pre-work or validation. In Kibana, these are often used for license checks. + +The Kibana Platform's HTTP interface does not provide this functionality, +however it is simple enough to port over using a higher-order function that can +wrap the route handler. + +#### Simple example + +In this simple example, a pre-handler is used to either abort the request with +an error or continue as normal. This is a simple "gate-keeping" pattern. + +```ts +// Legacy pre-handler +const licensePreRouting = (request) => { + const licenseInfo = getMyPluginLicenseInfo(request.server.plugins.xpack_main); + if (!licenseInfo.isOneOf(['gold', 'platinum', 'trial'])) { + throw Boom.forbidden(`You don't have the right license for MyPlugin!`); + } +} + +server.route({ + method: 'GET', + path: '/api/my-plugin/do-something', + config: { + pre: [{ method: licensePreRouting }] + }, + handler: (req) => { + return doSomethingInteresting(); + } +}) +``` + +In the Kibana Platform, the same functionality can be acheived by creating a +function that takes a route handler (or factory for a route handler) as an +argument and either invokes it in the successful case or returns an error +response in the failure case. + +We'll call this a "high-order handler" similar to the "high-order component" +pattern common in the React ecosystem. + +```ts +// New Platform high-order handler +const checkLicense = ( + handler: RequestHandler +): RequestHandler => { + return (context, req, res) => { + const licenseInfo = getMyPluginLicenseInfo(context.licensing.license); + + if (licenseInfo.hasAtLeast('gold')) { + return handler(context, req, res); + } else { + return res.forbidden({ body: `You don't have the right license for MyPlugin!` }); + } + } +} + +router.get( + { path: '/api/my-plugin/do-something', validate: false }, + checkLicense(async (context, req, res) => { + const results = doSomethingInteresting(); + return res.ok({ body: results }); + }), +) +``` + +#### Full Example + +In some cases, the route handler may need access to data that the pre-handler +retrieves. In this case, you can utilize a handler _factory_ rather than a raw +handler. + +```ts +// Legacy pre-handler +const licensePreRouting = (request) => { + const licenseInfo = getMyPluginLicenseInfo(request.server.plugins.xpack_main); + if (licenseInfo.isOneOf(['gold', 'platinum', 'trial'])) { + // In this case, the return value of the pre-handler is made available on + // whatever the 'assign' option is in the route config. + return licenseInfo; + } else { + // In this case, the route handler is never called and the user gets this + // error message + throw Boom.forbidden(`You don't have the right license for MyPlugin!`); + } +} + +server.route({ + method: 'GET', + path: '/api/my-plugin/do-something', + config: { + pre: [{ method: licensePreRouting, assign: 'licenseInfo' }] + }, + handler: (req) => { + const licenseInfo = req.pre.licenseInfo; + return doSomethingInteresting(licenseInfo); + } +}) +``` + +In many cases, it may be simpler to duplicate the function call +to retrieve the data again in the main handler. In this other cases, you can +utilize a handler _factory_ rather than a raw handler as the argument to your +high-order handler. This way the high-order handler can pass arbitrary arguments +to the route handler. + +```ts +// New Platform high-order handler +const checkLicense = ( + handlerFactory: (licenseInfo: MyPluginLicenseInfo) => RequestHandler +): RequestHandler => { + return (context, req, res) => { + const licenseInfo = getMyPluginLicenseInfo(context.licensing.license); + + if (licenseInfo.hasAtLeast('gold')) { + const handler = handlerFactory(licenseInfo); + return handler(context, req, res); + } else { + return res.forbidden({ body: `You don't have the right license for MyPlugin!` }); + } + } +} + +router.get( + { path: '/api/my-plugin/do-something', validate: false }, + checkLicense(licenseInfo => async (context, req, res) => { + const results = doSomethingInteresting(licenseInfo); + return res.ok({ body: results }); + }), +) +``` + ## Chrome In the Legacy Platform, the `ui/chrome` import contained APIs for a very wide From 81f3fbbf2546f33c980477ad617f910f313bdf78 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Thu, 30 Jan 2020 15:06:52 -0600 Subject: [PATCH 28/69] [APM] Service map center button (#56434) Add center button for service map. The fullscreen button is still there until #56351 is merged. Add fit and padding to the layout animation. Make the node labels wider so they aren't cut off. --- .../components/app/ServiceMap/Controls.tsx | 28 +++++++++++++++++-- .../app/ServiceMap/cytoscapeOptions.ts | 18 +++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx index 5b7ddc2b450d60..07ea97f442b7fa 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx @@ -4,12 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useState, useEffect } from 'react'; import { EuiButtonIcon, EuiPanel } from '@elastic/eui'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; +import React, { useContext, useEffect, useState } from 'react'; +import styled from 'styled-components'; import { CytoscapeContext } from './Cytoscape'; +import { animationOptions, nodeHeight } from './cytoscapeOptions'; import { FullscreenPanel } from './FullscreenPanel'; const ControlsContainer = styled('div')` @@ -58,6 +59,17 @@ export function Controls() { } }, [cy]); + function center() { + if (cy) { + const eles = cy.nodes(); + cy.animate({ + ...animationOptions, + center: { eles }, + fit: { eles, padding: nodeHeight } + }); + } + } + function zoomIn() { doZoom(cy, increment); } @@ -82,6 +94,9 @@ export function Controls() { const zoomOutLabel = i18n.translate('xpack.apm.serviceMap.zoomOut', { defaultMessage: 'Zoom out' }); + const centerLabel = i18n.translate('xpack.apm.serviceMap.center', { + defaultMessage: 'Center' + }); return ( @@ -103,6 +118,15 @@ export function Controls() { title={zoomOutLabel} /> + + ; + }; + + const ExtendedComponent = withActionOperations(ComponentToExtend); + const component = mount(); + component.find('button').simulate('click'); + + expect(actionApis.loadActionTypes).toHaveBeenCalledTimes(1); + expect(actionApis.loadActionTypes).toHaveBeenCalledWith({ http }); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_actions_api_operations.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_actions_api_operations.tsx new file mode 100644 index 00000000000000..45e6c6b10532ce --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_actions_api_operations.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { ActionType } from '../../../../types'; +import { useAppDependencies } from '../../../app_context'; +import { loadActionTypes } from '../../../lib/action_connector_api'; + +export interface ComponentOpts { + loadActionTypes: () => Promise; +} + +export type PropsWithOptionalApiHandlers = Omit & Partial; + +export function withActionOperations( + WrappedComponent: React.ComponentType +): React.FunctionComponent> { + return (props: PropsWithOptionalApiHandlers) => { + const { http } = useAppDependencies(); + return ( + loadActionTypes({ http })} /> + ); + }; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx new file mode 100644 index 00000000000000..30a065479ce33c --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx @@ -0,0 +1,269 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as React from 'react'; +import { shallow, mount } from 'enzyme'; +import uuid from 'uuid'; +import { withBulkAlertOperations, ComponentOpts } from './with_bulk_alert_api_operations'; +import * as alertApi from '../../../lib/alert_api'; +import { useAppDependencies } from '../../../app_context'; +import { Alert } from '../../../../types'; + +jest.mock('../../../lib/alert_api'); + +jest.mock('../../../app_context', () => { + const http = jest.fn(); + return { + useAppDependencies: jest.fn(() => ({ + http, + legacy: { + capabilities: { + get: jest.fn(() => ({})), + }, + }, + })), + }; +}); + +describe('with_bulk_alert_api_operations', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('extends any component with AlertApi methods', () => { + const ComponentToExtend = (props: ComponentOpts) => { + expect(typeof props.muteAlerts).toEqual('function'); + expect(typeof props.unmuteAlerts).toEqual('function'); + expect(typeof props.enableAlerts).toEqual('function'); + expect(typeof props.disableAlerts).toEqual('function'); + expect(typeof props.deleteAlerts).toEqual('function'); + expect(typeof props.muteAlert).toEqual('function'); + expect(typeof props.unmuteAlert).toEqual('function'); + expect(typeof props.enableAlert).toEqual('function'); + expect(typeof props.disableAlert).toEqual('function'); + expect(typeof props.deleteAlert).toEqual('function'); + expect(typeof props.loadAlert).toEqual('function'); + expect(typeof props.loadAlertTypes).toEqual('function'); + return
    ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + expect(shallow().type()).toEqual(ComponentToExtend); + }); + + // single alert + it('muteAlert calls the muteAlert api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ muteAlert, alert }: ComponentOpts & { alert: Alert }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alert = mockAlert(); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.muteAlert).toHaveBeenCalledTimes(1); + expect(alertApi.muteAlert).toHaveBeenCalledWith({ id: alert.id, http }); + }); + + it('unmuteAlert calls the unmuteAlert api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ unmuteAlert, alert }: ComponentOpts & { alert: Alert }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alert = mockAlert({ muteAll: true }); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.unmuteAlert).toHaveBeenCalledTimes(1); + expect(alertApi.unmuteAlert).toHaveBeenCalledWith({ id: alert.id, http }); + }); + + it('enableAlert calls the muteAlerts api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ enableAlert, alert }: ComponentOpts & { alert: Alert }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alert = mockAlert({ enabled: false }); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.enableAlert).toHaveBeenCalledTimes(1); + expect(alertApi.enableAlert).toHaveBeenCalledWith({ id: alert.id, http }); + }); + + it('disableAlert calls the disableAlert api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ disableAlert, alert }: ComponentOpts & { alert: Alert }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alert = mockAlert(); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.disableAlert).toHaveBeenCalledTimes(1); + expect(alertApi.disableAlert).toHaveBeenCalledWith({ id: alert.id, http }); + }); + + it('deleteAlert calls the deleteAlert api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ deleteAlert, alert }: ComponentOpts & { alert: Alert }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alert = mockAlert(); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.deleteAlert).toHaveBeenCalledTimes(1); + expect(alertApi.deleteAlert).toHaveBeenCalledWith({ id: alert.id, http }); + }); + + // bulk alerts + it('muteAlerts calls the muteAlerts api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ muteAlerts, alerts }: ComponentOpts & { alerts: Alert[] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alerts = [mockAlert(), mockAlert()]; + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.muteAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.muteAlerts).toHaveBeenCalledWith({ ids: [alerts[0].id, alerts[1].id], http }); + }); + + it('unmuteAlerts calls the unmuteAlerts api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ unmuteAlerts, alerts }: ComponentOpts & { alerts: Alert[] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alerts = [mockAlert({ muteAll: true }), mockAlert({ muteAll: true })]; + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.unmuteAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.unmuteAlerts).toHaveBeenCalledWith({ ids: [alerts[0].id, alerts[1].id], http }); + }); + + it('enableAlerts calls the muteAlertss api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ enableAlerts, alerts }: ComponentOpts & { alerts: Alert[] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alerts = [ + mockAlert({ enabled: false }), + mockAlert({ enabled: true }), + mockAlert({ enabled: false }), + ]; + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.enableAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.enableAlerts).toHaveBeenCalledWith({ ids: [alerts[0].id, alerts[2].id], http }); + }); + + it('disableAlerts calls the disableAlerts api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ disableAlerts, alerts }: ComponentOpts & { alerts: Alert[] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alerts = [mockAlert(), mockAlert()]; + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.disableAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.disableAlerts).toHaveBeenCalledWith({ + ids: [alerts[0].id, alerts[1].id], + http, + }); + }); + + it('deleteAlerts calls the deleteAlerts api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ deleteAlerts, alerts }: ComponentOpts & { alerts: Alert[] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alerts = [mockAlert(), mockAlert()]; + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.deleteAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.deleteAlerts).toHaveBeenCalledWith({ ids: [alerts[0].id, alerts[1].id], http }); + }); + + it('loadAlert calls the loadAlert api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ + loadAlert, + alertId, + }: ComponentOpts & { alertId: Alert['id'] }) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const alertId = uuid.v4(); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.loadAlert).toHaveBeenCalledTimes(1); + expect(alertApi.loadAlert).toHaveBeenCalledWith({ alertId, http }); + }); + + it('loadAlertTypes calls the loadAlertTypes api', () => { + const { http } = useAppDependencies(); + const ComponentToExtend = ({ loadAlertTypes }: ComponentOpts) => { + return ; + }; + + const ExtendedComponent = withBulkAlertOperations(ComponentToExtend); + const component = mount(); + component.find('button').simulate('click'); + + expect(alertApi.loadAlertTypes).toHaveBeenCalledTimes(1); + expect(alertApi.loadAlertTypes).toHaveBeenCalledWith({ http }); + }); +}); + +function mockAlert(overloads: Partial = {}): Alert { + return { + id: uuid.v4(), + enabled: true, + name: `alert-${uuid.v4()}`, + tags: [], + alertTypeId: '.noop', + consumer: 'consumer', + schedule: { interval: '1m' }, + actions: [], + params: {}, + createdBy: null, + updatedBy: null, + createdAt: new Date(), + updatedAt: new Date(), + apiKeyOwner: null, + throttle: null, + muteAll: false, + mutedInstanceIds: [], + ...overloads, + }; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.tsx new file mode 100644 index 00000000000000..c61ba631ab8685 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { Alert, AlertType } from '../../../../types'; +import { useAppDependencies } from '../../../app_context'; +import { + deleteAlerts, + disableAlerts, + enableAlerts, + muteAlerts, + unmuteAlerts, + deleteAlert, + disableAlert, + enableAlert, + muteAlert, + unmuteAlert, + loadAlert, + loadAlertTypes, +} from '../../../lib/alert_api'; + +export interface ComponentOpts { + muteAlerts: (alerts: Alert[]) => Promise; + unmuteAlerts: (alerts: Alert[]) => Promise; + enableAlerts: (alerts: Alert[]) => Promise; + disableAlerts: (alerts: Alert[]) => Promise; + deleteAlerts: (alerts: Alert[]) => Promise; + muteAlert: (alert: Alert) => Promise; + unmuteAlert: (alert: Alert) => Promise; + enableAlert: (alert: Alert) => Promise; + disableAlert: (alert: Alert) => Promise; + deleteAlert: (alert: Alert) => Promise; + loadAlert: (id: Alert['id']) => Promise; + loadAlertTypes: () => Promise; +} + +export type PropsWithOptionalApiHandlers = Omit & Partial; + +export function withBulkAlertOperations( + WrappedComponent: React.ComponentType +): React.FunctionComponent> { + return (props: PropsWithOptionalApiHandlers) => { + const { http } = useAppDependencies(); + return ( + + muteAlerts({ http, ids: items.filter(item => !isAlertMuted(item)).map(item => item.id) }) + } + unmuteAlerts={async (items: Alert[]) => + unmuteAlerts({ http, ids: items.filter(isAlertMuted).map(item => item.id) }) + } + enableAlerts={async (items: Alert[]) => + enableAlerts({ http, ids: items.filter(isAlertDisabled).map(item => item.id) }) + } + disableAlerts={async (items: Alert[]) => + disableAlerts({ + http, + ids: items.filter(item => !isAlertDisabled(item)).map(item => item.id), + }) + } + deleteAlerts={async (items: Alert[]) => + deleteAlerts({ http, ids: items.map(item => item.id) }) + } + muteAlert={async (alert: Alert) => { + if (!isAlertMuted(alert)) { + return muteAlert({ http, id: alert.id }); + } + }} + unmuteAlert={async (alert: Alert) => { + if (isAlertMuted(alert)) { + return unmuteAlert({ http, id: alert.id }); + } + }} + enableAlert={async (alert: Alert) => { + if (isAlertDisabled(alert)) { + return enableAlert({ http, id: alert.id }); + } + }} + disableAlert={async (alert: Alert) => { + if (!isAlertDisabled(alert)) { + return disableAlert({ http, id: alert.id }); + } + }} + deleteAlert={async (alert: Alert) => deleteAlert({ http, id: alert.id })} + loadAlert={async (alertId: Alert['id']) => loadAlert({ http, alertId })} + loadAlertTypes={async () => loadAlertTypes({ http })} + /> + ); + }; +} + +function isAlertDisabled(alert: Alert) { + return alert.enabled === false; +} + +function isAlertMuted(alert: Alert) { + return alert.muteAll === true; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index ed63ade903104c..7fb7d0bf48e4d2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import { TypeRegistry } from './application/type_registry'; -import { SanitizedAlert as Alert } from '../../../alerting/common'; -export { SanitizedAlert as Alert, AlertAction } from '../../../alerting/common'; +import { SanitizedAlert as Alert, AlertAction } from '../../../alerting/common'; +import { ActionType } from '../../../../../plugins/actions/common'; + +export { Alert, AlertAction }; +export { ActionType }; export type ActionTypeIndex = Record; export type AlertTypeIndex = Record; @@ -47,11 +50,6 @@ export interface ValidationResult { errors: Record; } -export interface ActionType { - id: string; - name: string; -} - export interface ActionConnector { secrets: Record; id: string; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts new file mode 100644 index 00000000000000..e8ed54571c77cd --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -0,0 +1,146 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import uuid from 'uuid'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header', 'alertDetailsUI']); + const browser = getService('browser'); + const alerting = getService('alerting'); + + describe('Alert Details', function() { + const testRunUuid = uuid.v4(); + + before(async () => { + await pageObjects.common.navigateToApp('triggersActions'); + + const actions = await Promise.all([ + alerting.actions.createAction({ + name: `server-log-${testRunUuid}-${0}`, + actionTypeId: '.server-log', + config: {}, + secrets: {}, + }), + alerting.actions.createAction({ + name: `server-log-${testRunUuid}-${1}`, + actionTypeId: '.server-log', + config: {}, + secrets: {}, + }), + ]); + + const alert = await alerting.alerts.createAlwaysFiringWithActions( + `test-alert-${testRunUuid}`, + actions.map(action => ({ + id: action.id, + group: 'default', + params: { + message: 'from alert 1s', + level: 'warn', + }, + })) + ); + + // refresh to see alert + await browser.refresh(); + + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Verify content + await testSubjects.existOrFail('alertsList'); + + // click on first alert + await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(alert.name); + }); + + it('renders the alert details', async () => { + const headingText = await pageObjects.alertDetailsUI.getHeadingText(); + expect(headingText).to.be(`test-alert-${testRunUuid}`); + + const alertType = await pageObjects.alertDetailsUI.getAlertType(); + expect(alertType).to.be(`Always Firing`); + + const { actionType, actionCount } = await pageObjects.alertDetailsUI.getActionsLabels(); + expect(actionType).to.be(`Server log`); + expect(actionCount).to.be(`+1`); + }); + + it('should disable the alert', async () => { + const enableSwitch = await testSubjects.find('enableSwitch'); + + const isChecked = await enableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); + + await enableSwitch.click(); + + const enabledSwitchAfterDisabling = await testSubjects.find('enableSwitch'); + const isCheckedAfterDisabling = await enabledSwitchAfterDisabling.getAttribute( + 'aria-checked' + ); + expect(isCheckedAfterDisabling).to.eql('false'); + }); + + it('shouldnt allow you to mute a disabled alert', async () => { + const disabledEnableSwitch = await testSubjects.find('enableSwitch'); + expect(await disabledEnableSwitch.getAttribute('aria-checked')).to.eql('false'); + + const muteSwitch = await testSubjects.find('muteSwitch'); + expect(await muteSwitch.getAttribute('aria-checked')).to.eql('false'); + + await muteSwitch.click(); + + const muteSwitchAfterTryingToMute = await testSubjects.find('muteSwitch'); + const isDisabledMuteAfterDisabling = await muteSwitchAfterTryingToMute.getAttribute( + 'aria-checked' + ); + expect(isDisabledMuteAfterDisabling).to.eql('false'); + }); + + it('should reenable a disabled the alert', async () => { + const enableSwitch = await testSubjects.find('enableSwitch'); + + const isChecked = await enableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); + + await enableSwitch.click(); + + const enabledSwitchAfterReenabling = await testSubjects.find('enableSwitch'); + const isCheckedAfterDisabling = await enabledSwitchAfterReenabling.getAttribute( + 'aria-checked' + ); + expect(isCheckedAfterDisabling).to.eql('true'); + }); + + it('should mute the alert', async () => { + const muteSwitch = await testSubjects.find('muteSwitch'); + + const isChecked = await muteSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); + + await muteSwitch.click(); + + const muteSwitchAfterDisabling = await testSubjects.find('muteSwitch'); + const isCheckedAfterDisabling = await muteSwitchAfterDisabling.getAttribute('aria-checked'); + expect(isCheckedAfterDisabling).to.eql('true'); + }); + + it('should unmute the alert', async () => { + const muteSwitch = await testSubjects.find('muteSwitch'); + + const isChecked = await muteSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); + + await muteSwitch.click(); + + const muteSwitchAfterUnmuting = await testSubjects.find('muteSwitch'); + const isCheckedAfterDisabling = await muteSwitchAfterUnmuting.getAttribute('aria-checked'); + expect(isCheckedAfterDisabling).to.eql('false'); + }); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 13f50a505b0b6f..307f39382a2363 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -12,6 +12,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); const log = getService('log'); const browser = getService('browser'); + const alerting = getService('alerting'); describe('Home page', function() { before(async () => { @@ -55,6 +56,43 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertsList'); }); + + it('navigates to an alert details page', async () => { + const action = await alerting.actions.createAction({ + name: `server-log-${Date.now()}`, + actionTypeId: '.server-log', + config: {}, + secrets: {}, + }); + + const alert = await alerting.alerts.createAlwaysFiringWithAction( + `test-alert-${Date.now()}`, + { + id: action.id, + group: 'default', + params: { + message: 'from alert 1s', + level: 'warn', + }, + } + ); + + // refresh to see alert + await browser.refresh(); + + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Verify content + await testSubjects.existOrFail('alertsList'); + + // click on first alert + await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(alert.name); + + // Verify url + expect(await browser.getCurrentUrl()).to.contain(`/alert/${alert.id}`); + + await alerting.alerts.deleteAlert(alert.id); + }); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index c76f477c8cfbef..a771fbf85e0b6e 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -12,5 +12,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); + loadTestFile(require.resolve('./details')); }); }; diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts index df651c67c2c281..43162e92563703 100644 --- a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts @@ -12,13 +12,42 @@ export default function(kibana: any) { require: ['alerting'], name: 'alerts', init(server: any) { - const noopAlertType: AlertType = { - id: 'test.noop', - name: 'Test: Noop', - actionGroups: ['default'], - async executor() {}, - }; - server.plugins.alerting.setup.registerType(noopAlertType); + createNoopAlertType(server.plugins.alerting.setup); + createAlwaysFiringAlertType(server.plugins.alerting.setup); }, }); } + +function createNoopAlertType(setupContract: any) { + const noopAlertType: AlertType = { + id: 'test.noop', + name: 'Test: Noop', + actionGroups: ['default'], + async executor() {}, + }; + setupContract.registerType(noopAlertType); +} + +function createAlwaysFiringAlertType(setupContract: any) { + // Alert types + const alwaysFiringAlertType: any = { + id: 'test.always-firing', + name: 'Always Firing', + actionGroups: ['default', 'other'], + async executor(alertExecutorOptions: any) { + const { services, state } = alertExecutorOptions; + + services + .alertInstanceFactory('1') + .replaceState({ instanceStateValue: true }) + .scheduleActions('default', { + instanceContextValue: true, + }); + return { + globalStateValue: true, + groupInSeriesIndex: (state.groupInSeriesIndex || 0) + 1, + }; + }, + }; + setupContract.registerType(alwaysFiringAlertType); +} diff --git a/x-pack/test/functional_with_es_ssl/page_objects/alert_details.ts b/x-pack/test/functional_with_es_ssl/page_objects/alert_details.ts new file mode 100644 index 00000000000000..6d2038a6ba04c3 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/page_objects/alert_details.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export function AlertDetailsPageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + + return { + async getHeadingText() { + return await testSubjects.getVisibleText('alertDetailsTitle'); + }, + async getAlertType() { + return await testSubjects.getVisibleText('alertTypeLabel'); + }, + async getActionsLabels() { + return { + actionType: await testSubjects.getVisibleText('actionTypeLabel'), + actionCount: await testSubjects.getVisibleText('actionCountLabel'), + }; + }, + }; +} diff --git a/x-pack/test/functional_with_es_ssl/page_objects/index.ts b/x-pack/test/functional_with_es_ssl/page_objects/index.ts index a068ba7dfe81d3..cfc44221a9c17f 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/index.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/index.ts @@ -6,8 +6,10 @@ import { pageObjects as xpackFunctionalPageObjects } from '../../functional/page_objects'; import { TriggersActionsPageProvider } from './triggers_actions_ui_page'; +import { AlertDetailsPageProvider } from './alert_details'; export const pageObjects = { ...xpackFunctionalPageObjects, triggersActionsUI: TriggersActionsPageProvider, + alertDetailsUI: AlertDetailsPageProvider, }; diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index a04ecc969a7e1f..ae66ac0ddddfb7 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -92,6 +92,10 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) }; }); }, + async clickOnAlertInAlertsList(name: string) { + await this.searchAlerts(name); + await find.clickDisplayedByCssSelector(`[data-test-subj="alertsList"] [title="${name}"]`); + }, async changeTabs(tab: 'alertsTab' | 'connectorsTab') { return await testSubjects.click(tab); }, diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/actions.ts b/x-pack/test/functional_with_es_ssl/services/alerting/actions.ts new file mode 100644 index 00000000000000..9454a32757068b --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/services/alerting/actions.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import axios, { AxiosInstance } from 'axios'; +import util from 'util'; +import { ToolingLog } from '@kbn/dev-utils'; + +export class Actions { + private log: ToolingLog; + private axios: AxiosInstance; + + constructor(url: string, log: ToolingLog) { + this.log = log; + this.axios = axios.create({ + headers: { 'kbn-xsrf': 'x-pack/ftr/services/alerting/actions' }, + baseURL: url, + maxRedirects: 0, + validateStatus: () => true, // we do our own validation below and throw better error messages + }); + } + + public async createAction(actionParams: { + name: string; + actionTypeId: string; + config: Record; + secrets: Record; + }) { + this.log.debug(`creating action ${actionParams.name}`); + + const { data: action, status: actionStatus, actionStatusText } = await this.axios.post( + `/api/action`, + actionParams + ); + if (actionStatus !== 200) { + throw new Error( + `Expected status code of 200, received ${actionStatus} ${actionStatusText}: ${util.inspect( + action + )}` + ); + } + + this.log.debug(`created action ${action.id}`); + return action; + } +} diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts new file mode 100644 index 00000000000000..1a31d4796d5bc4 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import axios, { AxiosInstance } from 'axios'; +import util from 'util'; +import { ToolingLog } from '@kbn/dev-utils'; + +export class Alerts { + private log: ToolingLog; + private axios: AxiosInstance; + + constructor(url: string, log: ToolingLog) { + this.log = log; + this.axios = axios.create({ + headers: { 'kbn-xsrf': 'x-pack/ftr/services/alerting/alerts' }, + baseURL: url, + maxRedirects: 0, + validateStatus: () => true, // we do our own validation below and throw better error messages + }); + } + + public async createAlwaysFiringWithActions( + name: string, + actions: Array<{ + id: string; + group: string; + params: Record; + }> + ) { + this.log.debug(`creating alert ${name}`); + + const { data: alert, status, statusText } = await this.axios.post(`/api/alert`, { + enabled: true, + name, + tags: ['foo'], + alertTypeId: 'test.always-firing', + consumer: 'bar', + schedule: { interval: '1m' }, + throttle: '1m', + actions, + params: {}, + }); + if (status !== 200) { + throw new Error( + `Expected status code of 200, received ${status} ${statusText}: ${util.inspect(alert)}` + ); + } + + this.log.debug(`created alert ${alert.id}`); + + return alert; + } + + public async createAlwaysFiringWithAction( + name: string, + action: { + id: string; + group: string; + params: Record; + } + ) { + return this.createAlwaysFiringWithActions(name, [action]); + } + + public async deleteAlert(id: string) { + this.log.debug(`deleting alert ${id}`); + + const { data: alert, status, statusText } = await this.axios.delete(`/api/alert/${id}`); + if (status !== 204) { + throw new Error( + `Expected status code of 204, received ${status} ${statusText}: ${util.inspect(alert)}` + ); + } + this.log.debug(`deleted alert ${alert.id}`); + } +} diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/index.ts b/x-pack/test/functional_with_es_ssl/services/alerting/index.ts new file mode 100644 index 00000000000000..e0aa827316c01a --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/services/alerting/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { format as formatUrl } from 'url'; + +import { Alerts } from './alerts'; +import { Actions } from './actions'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function AlertsServiceProvider({ getService }: FtrProviderContext) { + const log = getService('log'); + const config = getService('config'); + const url = formatUrl(config.get('servers.kibana')); + + return new (class AlertingService { + actions = new Actions(url, log); + alerts = new Alerts(url, log); + })(); +} diff --git a/x-pack/test/functional_with_es_ssl/services/index.ts b/x-pack/test/functional_with_es_ssl/services/index.ts index 6e96921c25a316..f04c2c980055d3 100644 --- a/x-pack/test/functional_with_es_ssl/services/index.ts +++ b/x-pack/test/functional_with_es_ssl/services/index.ts @@ -5,7 +5,9 @@ */ import { services as xpackFunctionalServices } from '../../functional/services'; +import { AlertsServiceProvider } from './alerting'; export const services = { ...xpackFunctionalServices, + alerting: AlertsServiceProvider, }; From 38dc1cbd3cb74baeb498978688c92683d42b974e Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Mon, 3 Feb 2020 12:03:50 +0100 Subject: [PATCH 56/69] Migrate es-archiver to typescript (#56008) * migrate lib/archives and lib/docs * migrate lib/indices * migrate end of /lib * migrate /actions * migrate es_archiver * migrate cli * migrate tests * use proper log stub * add Record typing Co-authored-by: Elastic Machine --- .../lib/config/read_config_file.ts | 2 +- src/es_archiver/actions/{edit.js => edit.ts} | 13 +- ..._kibana_index.js => empty_kibana_index.ts} | 18 +- .../actions/{index.js => index.ts} | 0 src/es_archiver/actions/{load.js => load.ts} | 29 +++- .../{rebuild_all.js => rebuild_all.ts} | 21 ++- src/es_archiver/actions/{save.js => save.ts} | 24 ++- .../actions/{unload.js => unload.ts} | 22 ++- src/es_archiver/{cli.js => cli.ts} | 22 +-- src/es_archiver/es_archiver.d.ts | 39 ----- .../{es_archiver.js => es_archiver.ts} | 33 ++-- src/es_archiver/index.js | 20 --- src/es_archiver/{index.d.ts => index.ts} | 0 .../lib/__tests__/{stats.js => stats.ts} | 18 +- .../__tests__/{format.js => format.ts} | 16 +- .../archives/__tests__/{parse.js => parse.ts} | 20 +-- .../archives/{constants.js => constants.ts} | 0 .../archives/{filenames.js => filenames.ts} | 6 +- .../lib/archives/{format.js => format.ts} | 4 +- .../lib/archives/{index.js => index.ts} | 2 - .../lib/archives/{parse.js => parse.ts} | 4 +- .../lib/{directory.js => directory.ts} | 5 +- ...ream.js => generate_doc_records_stream.ts} | 2 +- ..._stream.js => index_doc_records_stream.ts} | 4 +- .../lib/docs/__tests__/{stubs.js => stubs.ts} | 29 +++- ...ream.js => generate_doc_records_stream.ts} | 19 ++- .../lib/docs/{index.js => index.ts} | 0 ..._stream.js => index_doc_records_stream.ts} | 9 +- src/es_archiver/lib/{index.js => index.ts} | 2 +- ...index_stream.js => create_index_stream.ts} | 51 +++--- ...index_stream.js => delete_index_stream.ts} | 29 ++-- ...am.js => generate_index_records_stream.ts} | 14 +- .../lib/indices/__tests__/stubs.js | 128 --------------- .../lib/indices/__tests__/stubs.ts | 154 ++++++++++++++++++ ...index_stream.js => create_index_stream.ts} | 35 +++- .../{delete_index.js => delete_index.ts} | 34 ++-- ...index_stream.js => delete_index_stream.ts} | 10 +- ...am.js => generate_index_records_stream.ts} | 8 +- .../lib/indices/{index.js => index.ts} | 0 .../{kibana_index.js => kibana_index.ts} | 96 +++++++---- ...rds_stream.js => filter_records_stream.ts} | 2 +- ...rds_stream.js => filter_records_stream.ts} | 4 +- .../lib/records/{index.js => index.ts} | 0 src/es_archiver/lib/stats.ts | 2 + src/legacy/utils/index.d.ts | 13 ++ src/legacy/utils/streams/index.d.ts | 6 +- 46 files changed, 576 insertions(+), 393 deletions(-) rename src/es_archiver/actions/{edit.js => edit.ts} (91%) rename src/es_archiver/actions/{empty_kibana_index.js => empty_kibana_index.ts} (73%) rename src/es_archiver/actions/{index.js => index.ts} (100%) rename src/es_archiver/actions/{load.js => load.ts} (84%) rename src/es_archiver/actions/{rebuild_all.js => rebuild_all.ts} (84%) rename src/es_archiver/actions/{save.js => save.ts} (83%) rename src/es_archiver/actions/{unload.js => unload.ts} (79%) rename src/es_archiver/{cli.js => cli.ts} (90%) delete mode 100644 src/es_archiver/es_archiver.d.ts rename src/es_archiver/{es_archiver.js => es_archiver.ts} (83%) delete mode 100644 src/es_archiver/index.js rename src/es_archiver/{index.d.ts => index.ts} (100%) rename src/es_archiver/lib/__tests__/{stats.js => stats.ts} (95%) rename src/es_archiver/lib/archives/__tests__/{format.js => format.ts} (89%) rename src/es_archiver/lib/archives/__tests__/{parse.js => parse.ts} (93%) rename src/es_archiver/lib/archives/{constants.js => constants.ts} (100%) rename src/es_archiver/lib/archives/{filenames.js => filenames.ts} (91%) rename src/es_archiver/lib/archives/{format.js => format.ts} (93%) rename src/es_archiver/lib/archives/{index.js => index.ts} (99%) rename src/es_archiver/lib/archives/{parse.js => parse.ts} (91%) rename src/es_archiver/lib/{directory.js => directory.ts} (88%) rename src/es_archiver/lib/docs/__tests__/{generate_doc_records_stream.js => generate_doc_records_stream.ts} (98%) rename src/es_archiver/lib/docs/__tests__/{index_doc_records_stream.js => index_doc_records_stream.ts} (98%) rename src/es_archiver/lib/docs/__tests__/{stubs.js => stubs.ts} (74%) rename src/es_archiver/lib/docs/{generate_doc_records_stream.js => generate_doc_records_stream.ts} (80%) rename src/es_archiver/lib/docs/{index.js => index.ts} (100%) rename src/es_archiver/lib/docs/{index_doc_records_stream.js => index_doc_records_stream.ts} (86%) rename src/es_archiver/lib/{index.js => index.ts} (96%) rename src/es_archiver/lib/indices/__tests__/{create_index_stream.js => create_index_stream.ts} (76%) rename src/es_archiver/lib/indices/__tests__/{delete_index_stream.js => delete_index_stream.ts} (66%) rename src/es_archiver/lib/indices/__tests__/{generate_index_records_stream.js => generate_index_records_stream.ts} (89%) delete mode 100644 src/es_archiver/lib/indices/__tests__/stubs.js create mode 100644 src/es_archiver/lib/indices/__tests__/stubs.ts rename src/es_archiver/lib/indices/{create_index_stream.js => create_index_stream.ts} (81%) rename src/es_archiver/lib/indices/{delete_index.js => delete_index.ts} (76%) rename src/es_archiver/lib/indices/{delete_index_stream.js => delete_index_stream.ts} (86%) rename src/es_archiver/lib/indices/{generate_index_records_stream.js => generate_index_records_stream.ts} (89%) rename src/es_archiver/lib/indices/{index.js => index.ts} (100%) rename src/es_archiver/lib/indices/{kibana_index.js => kibana_index.ts} (70%) rename src/es_archiver/lib/records/__tests__/{filter_records_stream.js => filter_records_stream.ts} (97%) rename src/es_archiver/lib/records/{filter_records_stream.js => filter_records_stream.ts} (91%) rename src/es_archiver/lib/records/{index.js => index.ts} (100%) diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts index 72926cae7dbc4b..96fd525efa3ec8 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts @@ -56,7 +56,7 @@ async function getSettingsFromFile(log: ToolingLog, path: string, settingOverrid return transformDeprecations(settingsWithDefaults, logDeprecation); } -export async function readConfigFile(log: ToolingLog, path: string, settingOverrides: any) { +export async function readConfigFile(log: ToolingLog, path: string, settingOverrides: any = {}) { return new Config({ settings: await getSettingsFromFile(log, path, settingOverrides), primary: true, diff --git a/src/es_archiver/actions/edit.js b/src/es_archiver/actions/edit.ts similarity index 91% rename from src/es_archiver/actions/edit.js rename to src/es_archiver/actions/edit.ts index 5e3a3490133c71..de63081a1ea1b5 100644 --- a/src/es_archiver/actions/edit.js +++ b/src/es_archiver/actions/edit.ts @@ -22,12 +22,23 @@ import Fs from 'fs'; import { createGunzip, createGzip, Z_BEST_COMPRESSION } from 'zlib'; import { promisify } from 'util'; import globby from 'globby'; +import { ToolingLog } from '@kbn/dev-utils'; import { createPromiseFromStreams } from '../../legacy/utils'; const unlinkAsync = promisify(Fs.unlink); -export async function editAction({ prefix, dataDir, log, handler }) { +export async function editAction({ + prefix, + dataDir, + log, + handler, +}: { + prefix: string; + dataDir: string; + log: ToolingLog; + handler: () => Promise; +}) { const archives = ( await globby('**/*.gz', { cwd: prefix ? resolve(dataDir, prefix) : dataDir, diff --git a/src/es_archiver/actions/empty_kibana_index.js b/src/es_archiver/actions/empty_kibana_index.ts similarity index 73% rename from src/es_archiver/actions/empty_kibana_index.js rename to src/es_archiver/actions/empty_kibana_index.ts index 386863ec18a43d..5f96fbc5f996ca 100644 --- a/src/es_archiver/actions/empty_kibana_index.js +++ b/src/es_archiver/actions/empty_kibana_index.ts @@ -16,13 +16,25 @@ * specific language governing permissions and limitations * under the License. */ + +import { Client } from 'elasticsearch'; +import { ToolingLog, KbnClient } from '@kbn/dev-utils'; + import { migrateKibanaIndex, deleteKibanaIndices, createStats } from '../lib'; -export async function emptyKibanaIndexAction({ client, log, kbnClient }) { +export async function emptyKibanaIndexAction({ + client, + log, + kbnClient, +}: { + client: Client; + log: ToolingLog; + kbnClient: KbnClient; +}) { const stats = createStats('emptyKibanaIndex', log); const kibanaPluginIds = await kbnClient.plugins.getEnabledIds(); - await deleteKibanaIndices({ client, stats }); - await migrateKibanaIndex({ client, log, stats, kibanaPluginIds }); + await deleteKibanaIndices({ client, stats, log }); + await migrateKibanaIndex({ client, log, kibanaPluginIds }); return stats; } diff --git a/src/es_archiver/actions/index.js b/src/es_archiver/actions/index.ts similarity index 100% rename from src/es_archiver/actions/index.js rename to src/es_archiver/actions/index.ts diff --git a/src/es_archiver/actions/load.js b/src/es_archiver/actions/load.ts similarity index 84% rename from src/es_archiver/actions/load.js rename to src/es_archiver/actions/load.ts index ea02ce9dd3ad33..404fd0daea91d4 100644 --- a/src/es_archiver/actions/load.js +++ b/src/es_archiver/actions/load.ts @@ -19,6 +19,9 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; +import { Readable } from 'stream'; +import { ToolingLog, KbnClient } from '@kbn/dev-utils'; +import { Client } from 'elasticsearch'; import { createPromiseFromStreams, concatStreamProviders } from '../../legacy/utils'; @@ -38,12 +41,26 @@ import { // pipe a series of streams into each other so that data and errors // flow from the first stream to the last. Errors from the last stream // are not listened for -const pipeline = (...streams) => +const pipeline = (...streams: Readable[]) => streams.reduce((source, dest) => - source.once('error', error => dest.emit('error', error)).pipe(dest) + source.once('error', error => dest.emit('error', error)).pipe(dest as any) ); -export async function loadAction({ name, skipExisting, client, dataDir, log, kbnClient }) { +export async function loadAction({ + name, + skipExisting, + client, + dataDir, + log, + kbnClient, +}: { + name: string; + skipExisting: boolean; + client: Client; + dataDir: string; + log: ToolingLog; + kbnClient: KbnClient; +}) { const inputDir = resolve(dataDir, name); const stats = createStats(name, log); const files = prioritizeMappings(await readDirectory(inputDir)); @@ -64,12 +81,12 @@ export async function loadAction({ name, skipExisting, client, dataDir, log, kbn { objectMode: true } ); - const progress = new Progress('load progress'); + const progress = new Progress(); progress.activate(log); await createPromiseFromStreams([ recordStream, - createCreateIndexStream({ client, stats, skipExisting, log, kibanaPluginIds }), + createCreateIndexStream({ client, stats, skipExisting, log }), createIndexDocRecordsStream(client, stats, progress), ]); @@ -77,7 +94,7 @@ export async function loadAction({ name, skipExisting, client, dataDir, log, kbn const result = stats.toJSON(); for (const [index, { docs }] of Object.entries(result)) { - if (!docs && docs.indexed > 0) { + if (docs && docs.indexed > 0) { log.info('[%s] Indexed %d docs into %j', name, docs.indexed, index); } } diff --git a/src/es_archiver/actions/rebuild_all.js b/src/es_archiver/actions/rebuild_all.ts similarity index 84% rename from src/es_archiver/actions/rebuild_all.js rename to src/es_archiver/actions/rebuild_all.ts index 9379a29c38130c..1467a1d0430b76 100644 --- a/src/es_archiver/actions/rebuild_all.js +++ b/src/es_archiver/actions/rebuild_all.ts @@ -18,13 +18,12 @@ */ import { resolve, dirname, relative } from 'path'; - import { stat, rename, createReadStream, createWriteStream } from 'fs'; - +import { Readable, Writable } from 'stream'; import { fromNode } from 'bluebird'; +import { ToolingLog } from '@kbn/dev-utils'; import { createPromiseFromStreams } from '../../legacy/utils'; - import { prioritizeMappings, readDirectory, @@ -33,12 +32,20 @@ import { createFormatArchiveStreams, } from '../lib'; -async function isDirectory(path) { +async function isDirectory(path: string): Promise { const stats = await fromNode(cb => stat(path, cb)); return stats.isDirectory(); } -export async function rebuildAllAction({ dataDir, log, rootDir = dataDir }) { +export async function rebuildAllAction({ + dataDir, + log, + rootDir = dataDir, +}: { + dataDir: string; + log: ToolingLog; + rootDir?: string; +}) { const childNames = prioritizeMappings(await readDirectory(dataDir)); for (const childName of childNames) { const childPath = resolve(dataDir, childName); @@ -58,11 +65,11 @@ export async function rebuildAllAction({ dataDir, log, rootDir = dataDir }) { const tempFile = childPath + (gzip ? '.rebuilding.gz' : '.rebuilding'); await createPromiseFromStreams([ - createReadStream(childPath), + createReadStream(childPath) as Readable, ...createParseArchiveStreams({ gzip }), ...createFormatArchiveStreams({ gzip }), createWriteStream(tempFile), - ]); + ] as [Readable, ...Writable[]]); await fromNode(cb => rename(tempFile, childPath, cb)); log.info(`${archiveName} Rebuilt ${childName}`); diff --git a/src/es_archiver/actions/save.js b/src/es_archiver/actions/save.ts similarity index 83% rename from src/es_archiver/actions/save.js rename to src/es_archiver/actions/save.ts index 2c264ed2ee3a9e..7a3a9dd97c0ab1 100644 --- a/src/es_archiver/actions/save.js +++ b/src/es_archiver/actions/save.ts @@ -19,9 +19,11 @@ import { resolve } from 'path'; import { createWriteStream, mkdirSync } from 'fs'; +import { Readable, Writable } from 'stream'; +import { Client } from 'elasticsearch'; +import { ToolingLog } from '@kbn/dev-utils'; import { createListStream, createPromiseFromStreams } from '../../legacy/utils'; - import { createStats, createGenerateIndexRecordsStream, @@ -30,7 +32,21 @@ import { Progress, } from '../lib'; -export async function saveAction({ name, indices, client, dataDir, log, raw }) { +export async function saveAction({ + name, + indices, + client, + dataDir, + log, + raw, +}: { + name: string; + indices: string | string[]; + client: Client; + dataDir: string; + log: ToolingLog; + raw: boolean; +}) { const outputDir = resolve(dataDir, name); const stats = createStats(name, log); @@ -48,7 +64,7 @@ export async function saveAction({ name, indices, client, dataDir, log, raw }) { createGenerateIndexRecordsStream(client, stats), ...createFormatArchiveStreams(), createWriteStream(resolve(outputDir, 'mappings.json')), - ]), + ] as [Readable, ...Writable[]]), // export all documents from matching indexes into data.json.gz createPromiseFromStreams([ @@ -56,7 +72,7 @@ export async function saveAction({ name, indices, client, dataDir, log, raw }) { createGenerateDocRecordsStream(client, stats, progress), ...createFormatArchiveStreams({ gzip: !raw }), createWriteStream(resolve(outputDir, `data.json${raw ? '' : '.gz'}`)), - ]), + ] as [Readable, ...Writable[]]), ]); progress.deactivate(); diff --git a/src/es_archiver/actions/unload.js b/src/es_archiver/actions/unload.ts similarity index 79% rename from src/es_archiver/actions/unload.js rename to src/es_archiver/actions/unload.ts index 2acf8d2d719865..130a6b542b218a 100644 --- a/src/es_archiver/actions/unload.js +++ b/src/es_archiver/actions/unload.ts @@ -19,9 +19,11 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; +import { Readable, Writable } from 'stream'; +import { Client } from 'elasticsearch'; +import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { createPromiseFromStreams } from '../../legacy/utils'; - import { isGzip, createStats, @@ -32,7 +34,19 @@ import { createDeleteIndexStream, } from '../lib'; -export async function unloadAction({ name, client, dataDir, log, kbnClient }) { +export async function unloadAction({ + name, + client, + dataDir, + log, + kbnClient, +}: { + name: string; + client: Client; + dataDir: string; + log: ToolingLog; + kbnClient: KbnClient; +}) { const inputDir = resolve(dataDir, name); const stats = createStats(name, log); const kibanaPluginIds = await kbnClient.plugins.getEnabledIds(); @@ -42,11 +56,11 @@ export async function unloadAction({ name, client, dataDir, log, kbnClient }) { log.info('[%s] Unloading indices from %j', name, filename); await createPromiseFromStreams([ - createReadStream(resolve(inputDir, filename)), + createReadStream(resolve(inputDir, filename)) as Readable, ...createParseArchiveStreams({ gzip: isGzip(filename) }), createFilterRecordsStream('index'), createDeleteIndexStream(client, stats, log, kibanaPluginIds), - ]); + ] as [Readable, ...Writable[]]); } return stats.toJSON(); diff --git a/src/es_archiver/cli.js b/src/es_archiver/cli.ts similarity index 90% rename from src/es_archiver/cli.js rename to src/es_archiver/cli.ts index 56d1fdca89780c..252f99f8f47afb 100644 --- a/src/es_archiver/cli.js +++ b/src/es_archiver/cli.ts @@ -17,7 +17,7 @@ * under the License. */ -/************************************************************* +/** *********************************************************** * * Run `node scripts/es_archiver --help` for usage information * @@ -27,17 +27,17 @@ import { resolve } from 'path'; import { readFileSync } from 'fs'; import { format as formatUrl } from 'url'; import readline from 'readline'; - import { Command } from 'commander'; import * as legacyElasticsearch from 'elasticsearch'; -import { EsArchiver } from './es_archiver'; import { ToolingLog } from '@kbn/dev-utils'; import { readConfigFile } from '@kbn/test'; +import { EsArchiver } from './es_archiver'; + const cmd = new Command('node scripts/es_archiver'); -const resolveConfigPath = v => resolve(process.cwd(), v); +const resolveConfigPath = (v: string) => resolve(process.cwd(), v); const defaultConfigPath = resolveConfigPath('test/functional/config.js'); cmd @@ -56,6 +56,7 @@ cmd defaultConfigPath ) .on('--help', () => { + // eslint-disable-next-line no-console console.log(readFileSync(resolve(__dirname, './cli_help.txt'), 'utf8')); }); @@ -95,10 +96,10 @@ cmd output: process.stdout, }); - await new Promise(resolve => { + await new Promise(resolveInput => { rl.question(`Press enter when you're done`, () => { rl.close(); - resolve(); + resolveInput(); }); }); }) @@ -112,12 +113,12 @@ cmd cmd.parse(process.argv); -const missingCommand = cmd.args.every(a => !(a instanceof Command)); +const missingCommand = cmd.args.every(a => !((a as any) instanceof Command)); if (missingCommand) { execute(); } -async function execute(fn) { +async function execute(fn?: (esArchiver: EsArchiver, command: Command) => void): Promise { try { const log = new ToolingLog({ level: cmd.verbose ? 'debug' : 'info', @@ -134,7 +135,7 @@ async function execute(fn) { // log and count all validation errors let errorCount = 0; - const error = msg => { + const error = (msg: string) => { errorCount++; log.error(msg); }; @@ -170,11 +171,12 @@ async function execute(fn) { dataDir: resolve(cmd.dir), kibanaUrl: cmd.kibanaUrl, }); - await fn(esArchiver, cmd); + await fn!(esArchiver, cmd); } finally { await client.close(); } } catch (err) { + // eslint-disable-next-line no-console console.log('FATAL ERROR', err.stack); } } diff --git a/src/es_archiver/es_archiver.d.ts b/src/es_archiver/es_archiver.d.ts deleted file mode 100644 index c50ae19d99cbf3..00000000000000 --- a/src/es_archiver/es_archiver.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { ToolingLog } from '@kbn/dev-utils'; -import { Client } from 'elasticsearch'; -import { createStats } from './lib/stats'; - -export type JsonStats = ReturnType['toJSON']>; - -export class EsArchiver { - constructor(options: { client: Client; dataDir: string; log: ToolingLog; kibanaUrl: string }); - public save( - name: string, - indices: string | string[], - options?: { raw?: boolean } - ): Promise; - public load(name: string, options?: { skipExisting?: boolean }): Promise; - public unload(name: string): Promise; - public rebuildAll(): Promise; - public edit(prefix: string, handler: () => Promise): Promise; - public loadIfNeeded(name: string): Promise; - public emptyKibanaIndex(): Promise; -} diff --git a/src/es_archiver/es_archiver.js b/src/es_archiver/es_archiver.ts similarity index 83% rename from src/es_archiver/es_archiver.js rename to src/es_archiver/es_archiver.ts index 705706d0e58778..5614dfd842087b 100644 --- a/src/es_archiver/es_archiver.js +++ b/src/es_archiver/es_archiver.ts @@ -17,7 +17,8 @@ * under the License. */ -import { KbnClient } from '@kbn/dev-utils'; +import { Client } from 'elasticsearch'; +import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { saveAction, @@ -29,7 +30,22 @@ import { } from './actions'; export class EsArchiver { - constructor({ client, dataDir, log, kibanaUrl }) { + private readonly client: Client; + private readonly dataDir: string; + private readonly log: ToolingLog; + private readonly kbnClient: KbnClient; + + constructor({ + client, + dataDir, + log, + kibanaUrl, + }: { + client: Client; + dataDir: string; + log: ToolingLog; + kibanaUrl: string; + }) { this.client = client; this.dataDir = dataDir; this.log = log; @@ -46,7 +62,7 @@ export class EsArchiver { * @property {Boolean} options.raw - should the archive be raw (unzipped) or not * @return Promise */ - async save(name, indices, { raw = false } = {}) { + async save(name: string, indices: string | string[], { raw = false }: { raw?: boolean } = {}) { return await saveAction({ name, indices, @@ -66,9 +82,7 @@ export class EsArchiver { * be ignored or overwritten * @return Promise */ - async load(name, options = {}) { - const { skipExisting } = options; - + async load(name: string, { skipExisting = false }: { skipExisting?: boolean } = {}) { return await loadAction({ name, skipExisting: !!skipExisting, @@ -85,7 +99,7 @@ export class EsArchiver { * @param {String} name * @return Promise */ - async unload(name) { + async unload(name: string) { return await unloadAction({ name, client: this.client, @@ -103,7 +117,6 @@ export class EsArchiver { */ async rebuildAll() { return await rebuildAllAction({ - client: this.client, dataDir: this.dataDir, log: this.log, }); @@ -117,7 +130,7 @@ export class EsArchiver { * @param {() => Promise} handler * @return Promise */ - async edit(prefix, handler) { + async edit(prefix: string, handler: () => Promise) { return await editAction({ prefix, log: this.log, @@ -132,7 +145,7 @@ export class EsArchiver { * @param {String} name * @return Promise */ - async loadIfNeeded(name) { + async loadIfNeeded(name: string) { return await this.load(name, { skipExisting: true }); } diff --git a/src/es_archiver/index.js b/src/es_archiver/index.js deleted file mode 100644 index f7a579a98a42d9..00000000000000 --- a/src/es_archiver/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { EsArchiver } from './es_archiver'; diff --git a/src/es_archiver/index.d.ts b/src/es_archiver/index.ts similarity index 100% rename from src/es_archiver/index.d.ts rename to src/es_archiver/index.ts diff --git a/src/es_archiver/lib/__tests__/stats.js b/src/es_archiver/lib/__tests__/stats.ts similarity index 95% rename from src/es_archiver/lib/__tests__/stats.js rename to src/es_archiver/lib/__tests__/stats.ts index ccc24c25fb8601..28e337b3da5298 100644 --- a/src/es_archiver/lib/__tests__/stats.js +++ b/src/es_archiver/lib/__tests__/stats.ts @@ -17,26 +17,26 @@ * under the License. */ -import expect from '@kbn/expect'; import { uniq } from 'lodash'; import sinon from 'sinon'; +import expect from '@kbn/expect'; +import { ToolingLog } from '@kbn/dev-utils'; import { createStats } from '../'; -import { ToolingLog } from '@kbn/dev-utils'; -function createBufferedLog() { - const log = new ToolingLog({ +function createBufferedLog(): ToolingLog & { buffer: string } { + const log: ToolingLog = new ToolingLog({ level: 'debug', writeTo: { - write: chunk => (log.buffer += chunk), + write: chunk => ((log as any).buffer += chunk), }, }); - log.buffer = ''; - return log; + (log as any).buffer = ''; + return log as ToolingLog & { buffer: string }; } -function assertDeepClones(a, b) { - const path = []; +function assertDeepClones(a: any, b: any) { + const path: string[] = []; try { (function recurse(one, two) { if (typeof one !== 'object' || typeof two !== 'object') { diff --git a/src/es_archiver/lib/archives/__tests__/format.js b/src/es_archiver/lib/archives/__tests__/format.ts similarity index 89% rename from src/es_archiver/lib/archives/__tests__/format.js rename to src/es_archiver/lib/archives/__tests__/format.ts index 20ead30824d064..f472f094134d7b 100644 --- a/src/es_archiver/lib/archives/__tests__/format.js +++ b/src/es_archiver/lib/archives/__tests__/format.ts @@ -17,7 +17,7 @@ * under the License. */ -import Stream from 'stream'; +import Stream, { Readable, Writable } from 'stream'; import { createGunzip } from 'zlib'; import expect from '@kbn/expect'; @@ -43,11 +43,11 @@ describe('esArchiver createFormatArchiveStreams', () => { }); it('streams consume js values and produces buffers', async () => { - const output = await createPromiseFromStreams([ + const output = await createPromiseFromStreams([ createListStream(INPUTS), ...createFormatArchiveStreams({ gzip: false }), createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); expect(output.length).to.be.greaterThan(0); output.forEach(b => expect(b).to.be.a(Buffer)); @@ -58,7 +58,7 @@ describe('esArchiver createFormatArchiveStreams', () => { createListStream(INPUTS), ...createFormatArchiveStreams({ gzip: false }), createConcatStream(''), - ]); + ] as [Readable, ...Writable[]]); expect(json).to.be(INPUT_JSON); }); @@ -73,11 +73,11 @@ describe('esArchiver createFormatArchiveStreams', () => { }); it('streams consume js values and produces buffers', async () => { - const output = await createPromiseFromStreams([ + const output = await createPromiseFromStreams([ createListStream([1, 2, { foo: 'bar' }, [1, 2]]), ...createFormatArchiveStreams({ gzip: true }), createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); expect(output.length).to.be.greaterThan(0); output.forEach(b => expect(b).to.be.a(Buffer)); @@ -89,7 +89,7 @@ describe('esArchiver createFormatArchiveStreams', () => { ...createFormatArchiveStreams({ gzip: true }), createGunzip(), createConcatStream(''), - ]); + ] as [Readable, ...Writable[]]); expect(output).to.be(INPUT_JSON); }); }); @@ -100,7 +100,7 @@ describe('esArchiver createFormatArchiveStreams', () => { createListStream(INPUTS), ...createFormatArchiveStreams(), createConcatStream(''), - ]); + ] as [Readable, ...Writable[]]); expect(json).to.be(INPUT_JSON); }); diff --git a/src/es_archiver/lib/archives/__tests__/parse.js b/src/es_archiver/lib/archives/__tests__/parse.ts similarity index 93% rename from src/es_archiver/lib/archives/__tests__/parse.js rename to src/es_archiver/lib/archives/__tests__/parse.ts index 2e1506e543a358..ba30156b5af393 100644 --- a/src/es_archiver/lib/archives/__tests__/parse.js +++ b/src/es_archiver/lib/archives/__tests__/parse.ts @@ -17,7 +17,7 @@ * under the License. */ -import Stream, { PassThrough, Transform } from 'stream'; +import Stream, { PassThrough, Readable, Writable, Transform } from 'stream'; import { createGzip } from 'zlib'; import expect from '@kbn/expect'; @@ -66,13 +66,13 @@ describe('esArchiver createParseArchiveStreams', () => { ]), ...createParseArchiveStreams({ gzip: false }), createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); expect(output).to.eql([{ a: 1 }, 1]); }); it('provides each JSON object as soon as it is parsed', async () => { - let onReceived; + let onReceived: (resolved: any) => void; const receivedPromise = new Promise(resolve => (onReceived = resolve)); const input = new PassThrough(); const check = new Transform({ @@ -80,16 +80,16 @@ describe('esArchiver createParseArchiveStreams', () => { readableObjectMode: true, transform(chunk, env, callback) { onReceived(chunk); - callback(null, chunk); + callback(undefined, chunk); }, }); const finalPromise = createPromiseFromStreams([ - input, + input as Readable, ...createParseArchiveStreams(), check, createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); input.write(Buffer.from('{"a": 1}\n\n{"a":')); expect(await receivedPromise).to.eql({ a: 1 }); @@ -110,7 +110,7 @@ describe('esArchiver createParseArchiveStreams', () => { ]), ...createParseArchiveStreams({ gzip: false }), createConcatStream(), - ]); + ] as [Readable, ...Writable[]]); throw new Error('should have failed'); } catch (err) { expect(err.message).to.contain('Unexpected number'); @@ -149,7 +149,7 @@ describe('esArchiver createParseArchiveStreams', () => { createGzip(), ...createParseArchiveStreams({ gzip: true }), createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); expect(output).to.eql([{ a: 1 }, { a: 2 }]); }); @@ -161,7 +161,7 @@ describe('esArchiver createParseArchiveStreams', () => { createGzip(), ...createParseArchiveStreams({ gzip: true }), createConcatStream([]), - ]); + ] as [Readable, ...Writable[]]); expect(output).to.eql([]); }); @@ -173,7 +173,7 @@ describe('esArchiver createParseArchiveStreams', () => { createListStream([Buffer.from('{"a": 1}')]), ...createParseArchiveStreams({ gzip: true }), createConcatStream(), - ]); + ] as [Readable, ...Writable[]]); throw new Error('should have failed'); } catch (err) { expect(err.message).to.contain('incorrect header check'); diff --git a/src/es_archiver/lib/archives/constants.js b/src/es_archiver/lib/archives/constants.ts similarity index 100% rename from src/es_archiver/lib/archives/constants.js rename to src/es_archiver/lib/archives/constants.ts diff --git a/src/es_archiver/lib/archives/filenames.js b/src/es_archiver/lib/archives/filenames.ts similarity index 91% rename from src/es_archiver/lib/archives/filenames.js rename to src/es_archiver/lib/archives/filenames.ts index 4ced04401d28d5..24c355edda278a 100644 --- a/src/es_archiver/lib/archives/filenames.js +++ b/src/es_archiver/lib/archives/filenames.ts @@ -19,7 +19,7 @@ import { basename, extname } from 'path'; -export function isGzip(path) { +export function isGzip(path: string) { return extname(path) === '.gz'; } @@ -28,7 +28,7 @@ export function isGzip(path) { * @param {String} path * @return {Boolean} */ -export function isMappingFile(path) { +export function isMappingFile(path: string) { return basename(path, '.gz') === 'mappings.json'; } @@ -41,7 +41,7 @@ export function isMappingFile(path) { * @param {Array} filenames * @return {Array} */ -export function prioritizeMappings(filenames) { +export function prioritizeMappings(filenames: string[]) { return filenames.slice().sort((fa, fb) => { if (isMappingFile(fa) === isMappingFile(fb)) return 0; return isMappingFile(fb) ? 1 : -1; diff --git a/src/es_archiver/lib/archives/format.js b/src/es_archiver/lib/archives/format.ts similarity index 93% rename from src/es_archiver/lib/archives/format.js rename to src/es_archiver/lib/archives/format.ts index 01fca87e7ba988..9bef4c9adbf059 100644 --- a/src/es_archiver/lib/archives/format.js +++ b/src/es_archiver/lib/archives/format.ts @@ -19,14 +19,12 @@ import { createGzip, Z_BEST_COMPRESSION } from 'zlib'; import { PassThrough } from 'stream'; - import stringify from 'json-stable-stringify'; import { createMapStream, createIntersperseStream } from '../../../legacy/utils'; - import { RECORD_SEPARATOR } from './constants'; -export function createFormatArchiveStreams({ gzip = false } = {}) { +export function createFormatArchiveStreams({ gzip = false }: { gzip?: boolean } = {}) { return [ createMapStream(record => stringify(record, { space: ' ' })), createIntersperseStream(RECORD_SEPARATOR), diff --git a/src/es_archiver/lib/archives/index.js b/src/es_archiver/lib/archives/index.ts similarity index 99% rename from src/es_archiver/lib/archives/index.js rename to src/es_archiver/lib/archives/index.ts index 4020f52e45a35b..6aa489ea5a46de 100644 --- a/src/es_archiver/lib/archives/index.js +++ b/src/es_archiver/lib/archives/index.ts @@ -18,7 +18,5 @@ */ export { isGzip, prioritizeMappings } from './filenames'; - export { createParseArchiveStreams } from './parse'; - export { createFormatArchiveStreams } from './format'; diff --git a/src/es_archiver/lib/archives/parse.js b/src/es_archiver/lib/archives/parse.ts similarity index 91% rename from src/es_archiver/lib/archives/parse.js rename to src/es_archiver/lib/archives/parse.ts index 4fe1df72592292..0f4460c925019d 100644 --- a/src/es_archiver/lib/archives/parse.js +++ b/src/es_archiver/lib/archives/parse.ts @@ -29,7 +29,7 @@ export function createParseArchiveStreams({ gzip = false } = {}) { gzip ? createGunzip() : new PassThrough(), createReplaceStream('\r\n', '\n'), createSplitStream(RECORD_SEPARATOR), - createFilterStream(l => l.match(/[^\s]/)), - createMapStream(json => JSON.parse(json.trim())), + createFilterStream(l => !!l.match(/[^\s]/)), + createMapStream(json => JSON.parse(json.trim())), ]; } diff --git a/src/es_archiver/lib/directory.js b/src/es_archiver/lib/directory.ts similarity index 88% rename from src/es_archiver/lib/directory.js rename to src/es_archiver/lib/directory.ts index 5aee10cfea65d9..8581207fa795d1 100644 --- a/src/es_archiver/lib/directory.js +++ b/src/es_archiver/lib/directory.ts @@ -18,10 +18,9 @@ */ import { readdir } from 'fs'; - import { fromNode } from 'bluebird'; -export async function readDirectory(path) { - const allNames = await fromNode(cb => readdir(path, cb)); +export async function readDirectory(path: string) { + const allNames = await fromNode(cb => readdir(path, cb)); return allNames.filter(name => !name.startsWith('.')); } diff --git a/src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.js b/src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.ts similarity index 98% rename from src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.js rename to src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.ts index bf4aab208127f4..03599cdc9fbcfe 100644 --- a/src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.js +++ b/src/es_archiver/lib/docs/__tests__/generate_doc_records_stream.ts @@ -143,7 +143,7 @@ describe('esArchiver: createGenerateDocRecordsStream()', () => { }, }, ]); - sinon.assert.calledTwice(stats.archivedDoc); + sinon.assert.calledTwice(stats.archivedDoc as any); expect(progress.getTotal()).to.be(2); expect(progress.getComplete()).to.be(2); }); diff --git a/src/es_archiver/lib/docs/__tests__/index_doc_records_stream.js b/src/es_archiver/lib/docs/__tests__/index_doc_records_stream.ts similarity index 98% rename from src/es_archiver/lib/docs/__tests__/index_doc_records_stream.js rename to src/es_archiver/lib/docs/__tests__/index_doc_records_stream.ts index 2535642c27cc95..35b068a6910907 100644 --- a/src/es_archiver/lib/docs/__tests__/index_doc_records_stream.js +++ b/src/es_archiver/lib/docs/__tests__/index_doc_records_stream.ts @@ -26,12 +26,12 @@ import { Progress } from '../../progress'; import { createIndexDocRecordsStream } from '../index_doc_records_stream'; import { createStubStats, createStubClient, createPersonDocRecords } from './stubs'; -const recordsToBulkBody = records => { +const recordsToBulkBody = (records: any[]) => { return records.reduce((acc, record) => { const { index, id, source } = record.value; return [...acc, { index: { _index: index, _id: id } }, source]; - }, []); + }, [] as any[]); }; describe('esArchiver: createIndexDocRecordsStream()', () => { diff --git a/src/es_archiver/lib/docs/__tests__/stubs.js b/src/es_archiver/lib/docs/__tests__/stubs.ts similarity index 74% rename from src/es_archiver/lib/docs/__tests__/stubs.js rename to src/es_archiver/lib/docs/__tests__/stubs.ts index 9ed48efa7d03ac..698d62e450cb46 100644 --- a/src/es_archiver/lib/docs/__tests__/stubs.js +++ b/src/es_archiver/lib/docs/__tests__/stubs.ts @@ -17,17 +17,22 @@ * under the License. */ +import { Client } from 'elasticsearch'; import sinon from 'sinon'; import Chance from 'chance'; import { times } from 'lodash'; + +import { Stats } from '../../stats'; + const chance = new Chance(); -export const createStubStats = () => ({ - indexedDoc: sinon.stub(), - archivedDoc: sinon.stub(), -}); +export const createStubStats = (): Stats => + ({ + indexedDoc: sinon.stub(), + archivedDoc: sinon.stub(), + } as any); -export const createPersonDocRecords = n => +export const createPersonDocRecords = (n: number) => times(n, () => ({ type: 'doc', value: { @@ -42,15 +47,21 @@ export const createPersonDocRecords = n => }, })); -export const createStubClient = (responses = []) => { - const createStubClientMethod = name => +type MockClient = Client & { + assertNoPendingResponses: () => void; +}; + +export const createStubClient = ( + responses: Array<(name: string, params: any) => any | Promise> = [] +): MockClient => { + const createStubClientMethod = (name: string) => sinon.spy(async params => { if (responses.length === 0) { throw new Error(`unexpected client.${name} call`); } const response = responses.shift(); - return await response(name, params); + return await response!(name, params); }); return { @@ -63,5 +74,5 @@ export const createStubClient = (responses = []) => { throw new Error(`There are ${responses.length} unsent responses.`); } }, - }; + } as any; }; diff --git a/src/es_archiver/lib/docs/generate_doc_records_stream.js b/src/es_archiver/lib/docs/generate_doc_records_stream.ts similarity index 80% rename from src/es_archiver/lib/docs/generate_doc_records_stream.js rename to src/es_archiver/lib/docs/generate_doc_records_stream.ts index be8b0351d95c8e..e255a0abc36c5f 100644 --- a/src/es_archiver/lib/docs/generate_doc_records_stream.js +++ b/src/es_archiver/lib/docs/generate_doc_records_stream.ts @@ -18,33 +18,36 @@ */ import { Transform } from 'stream'; +import { Client, SearchParams, SearchResponse } from 'elasticsearch'; +import { Stats } from '../stats'; +import { Progress } from '../progress'; const SCROLL_SIZE = 1000; const SCROLL_TIMEOUT = '1m'; -export function createGenerateDocRecordsStream(client, stats, progress) { +export function createGenerateDocRecordsStream(client: Client, stats: Stats, progress: Progress) { return new Transform({ writableObjectMode: true, readableObjectMode: true, async transform(index, enc, callback) { try { - let remainingHits = null; - let resp = null; + let remainingHits = 0; + let resp: SearchResponse | null = null; while (!resp || remainingHits > 0) { if (!resp) { resp = await client.search({ - index: index, + index, scroll: SCROLL_TIMEOUT, size: SCROLL_SIZE, _source: true, - rest_total_hits_as_int: true, - }); + rest_total_hits_as_int: true, // not declared on SearchParams type + } as SearchParams); remainingHits = resp.hits.total; progress.addToTotal(remainingHits); } else { resp = await client.scroll({ - scrollId: resp._scroll_id, + scrollId: resp._scroll_id!, scroll: SCROLL_TIMEOUT, }); } @@ -68,7 +71,7 @@ export function createGenerateDocRecordsStream(client, stats, progress) { progress.addToComplete(resp.hits.hits.length); } - callback(null); + callback(undefined); } catch (err) { callback(err); } diff --git a/src/es_archiver/lib/docs/index.js b/src/es_archiver/lib/docs/index.ts similarity index 100% rename from src/es_archiver/lib/docs/index.js rename to src/es_archiver/lib/docs/index.ts diff --git a/src/es_archiver/lib/docs/index_doc_records_stream.js b/src/es_archiver/lib/docs/index_doc_records_stream.ts similarity index 86% rename from src/es_archiver/lib/docs/index_doc_records_stream.js rename to src/es_archiver/lib/docs/index_doc_records_stream.ts index 73fb75c52ff0a6..8236ae8adb6db7 100644 --- a/src/es_archiver/lib/docs/index_doc_records_stream.js +++ b/src/es_archiver/lib/docs/index_doc_records_stream.ts @@ -17,11 +17,14 @@ * under the License. */ +import { Client } from 'elasticsearch'; import { Writable } from 'stream'; +import { Stats } from '../stats'; +import { Progress } from '../progress'; -export function createIndexDocRecordsStream(client, stats, progress) { - async function indexDocs(docs) { - const body = []; +export function createIndexDocRecordsStream(client: Client, stats: Stats, progress: Progress) { + async function indexDocs(docs: any[]) { + const body: any[] = []; docs.forEach(doc => { stats.indexedDoc(doc.index); diff --git a/src/es_archiver/lib/index.js b/src/es_archiver/lib/index.ts similarity index 96% rename from src/es_archiver/lib/index.js rename to src/es_archiver/lib/index.ts index 246dd8169cd6b0..960d51e411859e 100644 --- a/src/es_archiver/lib/index.js +++ b/src/es_archiver/lib/index.ts @@ -30,7 +30,7 @@ export { export { createFilterRecordsStream } from './records'; -export { createStats } from './stats'; +export { createStats, Stats } from './stats'; export { isGzip, diff --git a/src/es_archiver/lib/indices/__tests__/create_index_stream.js b/src/es_archiver/lib/indices/__tests__/create_index_stream.ts similarity index 76% rename from src/es_archiver/lib/indices/__tests__/create_index_stream.js rename to src/es_archiver/lib/indices/__tests__/create_index_stream.ts index 9e0f83c9f7eb96..c90497eded88ce 100644 --- a/src/es_archiver/lib/indices/__tests__/create_index_stream.js +++ b/src/es_archiver/lib/indices/__tests__/create_index_stream.ts @@ -34,10 +34,13 @@ import { createStubIndexRecord, createStubDocRecord, createStubClient, + createStubLogger, } from './stubs'; const chance = new Chance(); +const log = createStubLogger(); + describe('esArchiver: createCreateIndexStream()', () => { describe('defaults', () => { it('deletes existing indices, creates all', async () => { @@ -48,15 +51,15 @@ describe('esArchiver: createCreateIndexStream()', () => { createStubIndexRecord('existing-index'), createStubIndexRecord('new-index'), ]), - createCreateIndexStream({ client, stats }), + createCreateIndexStream({ client, stats, log }), ]); expect(stats.getTestSummary()).to.eql({ deletedIndex: 1, createdIndex: 2, }); - sinon.assert.callCount(client.indices.delete, 1); - sinon.assert.callCount(client.indices.create, 3); // one failed create because of existing + sinon.assert.callCount(client.indices.delete as sinon.SinonSpy, 1); + sinon.assert.callCount(client.indices.create as sinon.SinonSpy, 3); // one failed create because of existing }); it('deletes existing aliases, creates all', async () => { @@ -67,14 +70,19 @@ describe('esArchiver: createCreateIndexStream()', () => { createStubIndexRecord('existing-index'), createStubIndexRecord('new-index'), ]), - createCreateIndexStream({ client, stats, log: { debug: () => {} } }), + createCreateIndexStream({ client, stats, log }), ]); - expect(client.indices.getAlias.calledOnce).to.be.ok(); - expect(client.indices.getAlias.args[0][0]).to.eql({ name: 'existing-index', ignore: [404] }); - expect(client.indices.delete.calledOnce).to.be.ok(); - expect(client.indices.delete.args[0][0]).to.eql({ index: ['actual-index'] }); - sinon.assert.callCount(client.indices.create, 3); // one failed create because of existing + expect((client.indices.getAlias as sinon.SinonSpy).calledOnce).to.be.ok(); + expect((client.indices.getAlias as sinon.SinonSpy).args[0][0]).to.eql({ + name: 'existing-index', + ignore: [404], + }); + expect((client.indices.delete as sinon.SinonSpy).calledOnce).to.be.ok(); + expect((client.indices.delete as sinon.SinonSpy).args[0][0]).to.eql({ + index: ['actual-index'], + }); + sinon.assert.callCount(client.indices.create as sinon.SinonSpy, 3); // one failed create because of existing }); it('passes through "hit" records', async () => { @@ -86,7 +94,7 @@ describe('esArchiver: createCreateIndexStream()', () => { createStubDocRecord('index', 1), createStubDocRecord('index', 2), ]), - createCreateIndexStream({ client, stats }), + createCreateIndexStream({ client, stats, log }), createConcatStream([]), ]); @@ -101,11 +109,11 @@ describe('esArchiver: createCreateIndexStream()', () => { createStubIndexRecord('index', { foo: {} }), createStubDocRecord('index', 1), ]), - createCreateIndexStream({ client, stats }), + createCreateIndexStream({ client, stats, log }), createConcatStream([]), ]); - sinon.assert.calledWith(client.indices.create, { + sinon.assert.calledWith(client.indices.create as sinon.SinonSpy, { method: 'PUT', index: 'index', body: { @@ -126,7 +134,7 @@ describe('esArchiver: createCreateIndexStream()', () => { const output = await createPromiseFromStreams([ createListStream([createStubIndexRecord('index'), ...randoms]), - createCreateIndexStream({ client, stats }), + createCreateIndexStream({ client, stats, log }), createConcatStream([]), ]); @@ -140,7 +148,7 @@ describe('esArchiver: createCreateIndexStream()', () => { const output = await createPromiseFromStreams([ createListStream(nonRecordValues), - createCreateIndexStream({ client, stats }), + createCreateIndexStream({ client, stats, log }), createConcatStream([]), ]); @@ -161,6 +169,7 @@ describe('esArchiver: createCreateIndexStream()', () => { createCreateIndexStream({ client, stats, + log, skipExisting: true, }), ]); @@ -169,9 +178,12 @@ describe('esArchiver: createCreateIndexStream()', () => { skippedIndex: 1, createdIndex: 1, }); - sinon.assert.callCount(client.indices.delete, 0); - sinon.assert.callCount(client.indices.create, 2); // one failed create because of existing - expect(client.indices.create.args[0][0]).to.have.property('index', 'new-index'); + sinon.assert.callCount(client.indices.delete as sinon.SinonSpy, 0); + sinon.assert.callCount(client.indices.create as sinon.SinonSpy, 2); // one failed create because of existing + expect((client.indices.create as sinon.SinonSpy).args[0][0]).to.have.property( + 'index', + 'new-index' + ); }); it('filters documents for skipped indices', async () => { @@ -190,6 +202,7 @@ describe('esArchiver: createCreateIndexStream()', () => { createCreateIndexStream({ client, stats, + log, skipExisting: true, }), createConcatStream([]), @@ -199,8 +212,8 @@ describe('esArchiver: createCreateIndexStream()', () => { skippedIndex: 1, createdIndex: 1, }); - sinon.assert.callCount(client.indices.delete, 0); - sinon.assert.callCount(client.indices.create, 2); // one failed create because of existing + sinon.assert.callCount(client.indices.delete as sinon.SinonSpy, 0); + sinon.assert.callCount(client.indices.create as sinon.SinonSpy, 2); // one failed create because of existing expect(output).to.have.length(2); expect(output).to.eql([ diff --git a/src/es_archiver/lib/indices/__tests__/delete_index_stream.js b/src/es_archiver/lib/indices/__tests__/delete_index_stream.ts similarity index 66% rename from src/es_archiver/lib/indices/__tests__/delete_index_stream.js rename to src/es_archiver/lib/indices/__tests__/delete_index_stream.ts index 955d1fff8779ed..1c989ba158a29d 100644 --- a/src/es_archiver/lib/indices/__tests__/delete_index_stream.js +++ b/src/es_archiver/lib/indices/__tests__/delete_index_stream.ts @@ -23,7 +23,14 @@ import { createListStream, createPromiseFromStreams } from '../../../../legacy/u import { createDeleteIndexStream } from '../delete_index_stream'; -import { createStubStats, createStubClient, createStubIndexRecord } from './stubs'; +import { + createStubStats, + createStubClient, + createStubIndexRecord, + createStubLogger, +} from './stubs'; + +const log = createStubLogger(); describe('esArchiver: createDeleteIndexStream()', () => { it('deletes the index without checking if it exists', async () => { @@ -32,13 +39,13 @@ describe('esArchiver: createDeleteIndexStream()', () => { await createPromiseFromStreams([ createListStream([createStubIndexRecord('index1')]), - createDeleteIndexStream(client, stats), + createDeleteIndexStream(client, stats, log, []), ]); - sinon.assert.notCalled(stats.deletedIndex); - sinon.assert.notCalled(client.indices.create); - sinon.assert.calledOnce(client.indices.delete); - sinon.assert.notCalled(client.indices.exists); + sinon.assert.notCalled(stats.deletedIndex as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.create as sinon.SinonSpy); + sinon.assert.calledOnce(client.indices.delete as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.exists as sinon.SinonSpy); }); it('reports the delete when the index existed', async () => { @@ -47,12 +54,12 @@ describe('esArchiver: createDeleteIndexStream()', () => { await createPromiseFromStreams([ createListStream([createStubIndexRecord('index1')]), - createDeleteIndexStream(client, stats), + createDeleteIndexStream(client, stats, log, []), ]); - sinon.assert.calledOnce(stats.deletedIndex); - sinon.assert.notCalled(client.indices.create); - sinon.assert.calledOnce(client.indices.delete); - sinon.assert.notCalled(client.indices.exists); + sinon.assert.calledOnce(stats.deletedIndex as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.create as sinon.SinonSpy); + sinon.assert.calledOnce(client.indices.delete as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.exists as sinon.SinonSpy); }); }); diff --git a/src/es_archiver/lib/indices/__tests__/generate_index_records_stream.js b/src/es_archiver/lib/indices/__tests__/generate_index_records_stream.ts similarity index 89% rename from src/es_archiver/lib/indices/__tests__/generate_index_records_stream.js rename to src/es_archiver/lib/indices/__tests__/generate_index_records_stream.ts index 3523e9e82b153f..7a3712ca1a336f 100644 --- a/src/es_archiver/lib/indices/__tests__/generate_index_records_stream.js +++ b/src/es_archiver/lib/indices/__tests__/generate_index_records_stream.ts @@ -45,10 +45,10 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { archivedIndex: 4, }); - sinon.assert.callCount(client.indices.get, 4); - sinon.assert.notCalled(client.indices.create); - sinon.assert.notCalled(client.indices.delete); - sinon.assert.notCalled(client.indices.exists); + sinon.assert.callCount(client.indices.get as sinon.SinonSpy, 4); + sinon.assert.notCalled(client.indices.create as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.delete as sinon.SinonSpy); + sinon.assert.notCalled(client.indices.exists as sinon.SinonSpy); }); it('filters index metadata from settings', async () => { @@ -60,9 +60,9 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { createGenerateIndexRecordsStream(client, stats), ]); - const params = client.indices.get.args[0][0]; + const params = (client.indices.get as sinon.SinonSpy).args[0][0]; expect(params).to.have.property('filterPath'); - const filters = params.filterPath; + const filters: string[] = params.filterPath; expect(filters.some(path => path.includes('index.creation_date'))).to.be(true); expect(filters.some(path => path.includes('index.uuid'))).to.be(true); expect(filters.some(path => path.includes('index.version'))).to.be(true); @@ -73,7 +73,7 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { const stats = createStubStats(); const client = createStubClient(['index1', 'index2', 'index3']); - const indexRecords = await createPromiseFromStreams([ + const indexRecords = await createPromiseFromStreams([ createListStream(['index1', 'index2', 'index3']), createGenerateIndexRecordsStream(client, stats), createConcatStream([]), diff --git a/src/es_archiver/lib/indices/__tests__/stubs.js b/src/es_archiver/lib/indices/__tests__/stubs.js deleted file mode 100644 index 00649a06f9efef..00000000000000 --- a/src/es_archiver/lib/indices/__tests__/stubs.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import sinon from 'sinon'; - -export const createStubStats = () => ({ - createdIndex: sinon.stub(), - createdAliases: sinon.stub(), - deletedIndex: sinon.stub(), - skippedIndex: sinon.stub(), - archivedIndex: sinon.stub(), - getTestSummary() { - const summary = {}; - Object.keys(this).forEach(key => { - if (this[key].callCount) { - summary[key] = this[key].callCount; - } - }); - return summary; - }, -}); - -export const createStubIndexRecord = (index, aliases = {}) => ({ - type: 'index', - value: { index, aliases }, -}); - -export const createStubDocRecord = (index, id) => ({ - type: 'doc', - value: { index, id }, -}); - -const createEsClientError = errorType => { - const err = new Error(`ES Client Error Stub "${errorType}"`); - err.body = { - error: { - type: errorType, - }, - }; - return err; -}; - -const indexAlias = (aliases, index) => Object.keys(aliases).find(k => aliases[k] === index); - -export const createStubClient = (existingIndices = [], aliases = {}) => ({ - indices: { - get: sinon.spy(async ({ index }) => { - if (!existingIndices.includes(index)) { - throw createEsClientError('index_not_found_exception'); - } - - return { - [index]: { - mappings: {}, - settings: {}, - }, - }; - }), - existsAlias: sinon.spy(({ name }) => { - return Promise.resolve(aliases.hasOwnProperty(name)); - }), - getAlias: sinon.spy(async ({ index, name }) => { - if (index && existingIndices.indexOf(index) >= 0) { - const result = indexAlias(aliases, index); - return { [index]: { aliases: result ? { [result]: {} } : {} } }; - } - - if (name && aliases[name]) { - return { [aliases[name]]: { aliases: { [name]: {} } } }; - } - - return { status: 404 }; - }), - updateAliases: sinon.spy(async ({ body }) => { - body.actions.forEach(({ add: { index, alias } }) => { - if (!existingIndices.includes(index)) { - throw createEsClientError('index_not_found_exception'); - } - existingIndices.push({ index, alias }); - }); - - return { ok: true }; - }), - create: sinon.spy(async ({ index }) => { - if (existingIndices.includes(index) || aliases.hasOwnProperty(index)) { - throw createEsClientError('resource_already_exists_exception'); - } else { - existingIndices.push(index); - return { ok: true }; - } - }), - delete: sinon.spy(async ({ index }) => { - const indices = Array.isArray(index) ? index : [index]; - if (indices.every(ix => existingIndices.includes(ix))) { - // Delete aliases associated with our indices - indices.forEach(ix => { - const alias = Object.keys(aliases).find(k => aliases[k] === ix); - if (alias) { - delete aliases[alias]; - } - }); - indices.forEach(ix => existingIndices.splice(existingIndices.indexOf(ix), 1)); - return { ok: true }; - } else { - throw createEsClientError('index_not_found_exception'); - } - }), - exists: sinon.spy(async () => { - throw new Error('Do not use indices.exists(). React to errors instead.'); - }), - }, -}); diff --git a/src/es_archiver/lib/indices/__tests__/stubs.ts b/src/es_archiver/lib/indices/__tests__/stubs.ts new file mode 100644 index 00000000000000..3f4682299c38d8 --- /dev/null +++ b/src/es_archiver/lib/indices/__tests__/stubs.ts @@ -0,0 +1,154 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Client } from 'elasticsearch'; +import sinon from 'sinon'; +import { ToolingLog } from '@kbn/dev-utils'; +import { Stats } from '../../stats'; + +type StubStats = Stats & { + getTestSummary: () => Record; +}; + +export const createStubStats = (): StubStats => + ({ + createdIndex: sinon.stub(), + createdAliases: sinon.stub(), + deletedIndex: sinon.stub(), + skippedIndex: sinon.stub(), + archivedIndex: sinon.stub(), + getTestSummary() { + const summary: Record = {}; + Object.keys(this).forEach(key => { + if (this[key].callCount) { + summary[key] = this[key].callCount; + } + }); + return summary; + }, + } as any); + +export const createStubLogger = (): ToolingLog => + ({ + debug: sinon.stub(), + info: sinon.stub(), + success: sinon.stub(), + warning: sinon.stub(), + error: sinon.stub(), + } as any); + +export const createStubIndexRecord = (index: string, aliases = {}) => ({ + type: 'index', + value: { index, aliases }, +}); + +export const createStubDocRecord = (index: string, id: number) => ({ + type: 'doc', + value: { index, id }, +}); + +const createEsClientError = (errorType: string) => { + const err = new Error(`ES Client Error Stub "${errorType}"`); + (err as any).body = { + error: { + type: errorType, + }, + }; + return err; +}; + +const indexAlias = (aliases: Record, index: string) => + Object.keys(aliases).find(k => aliases[k] === index); + +type StubClient = Client; + +export const createStubClient = ( + existingIndices: string[] = [], + aliases: Record = {} +): StubClient => + ({ + indices: { + get: sinon.spy(async ({ index }) => { + if (!existingIndices.includes(index)) { + throw createEsClientError('index_not_found_exception'); + } + + return { + [index]: { + mappings: {}, + settings: {}, + }, + }; + }), + existsAlias: sinon.spy(({ name }) => { + return Promise.resolve(aliases.hasOwnProperty(name)); + }), + getAlias: sinon.spy(async ({ index, name }) => { + if (index && existingIndices.indexOf(index) >= 0) { + const result = indexAlias(aliases, index); + return { [index]: { aliases: result ? { [result]: {} } : {} } }; + } + + if (name && aliases[name]) { + return { [aliases[name]]: { aliases: { [name]: {} } } }; + } + + return { status: 404 }; + }), + updateAliases: sinon.spy(async ({ body }) => { + body.actions.forEach( + ({ add: { index, alias } }: { add: { index: string; alias: string } }) => { + if (!existingIndices.includes(index)) { + throw createEsClientError('index_not_found_exception'); + } + existingIndices.push({ index, alias } as any); + } + ); + + return { ok: true }; + }), + create: sinon.spy(async ({ index }) => { + if (existingIndices.includes(index) || aliases.hasOwnProperty(index)) { + throw createEsClientError('resource_already_exists_exception'); + } else { + existingIndices.push(index); + return { ok: true }; + } + }), + delete: sinon.spy(async ({ index }) => { + const indices = Array.isArray(index) ? index : [index]; + if (indices.every(ix => existingIndices.includes(ix))) { + // Delete aliases associated with our indices + indices.forEach(ix => { + const alias = Object.keys(aliases).find(k => aliases[k] === ix); + if (alias) { + delete aliases[alias]; + } + }); + indices.forEach(ix => existingIndices.splice(existingIndices.indexOf(ix), 1)); + return { ok: true }; + } else { + throw createEsClientError('index_not_found_exception'); + } + }), + exists: sinon.spy(async () => { + throw new Error('Do not use indices.exists(). React to errors instead.'); + }), + }, + } as any); diff --git a/src/es_archiver/lib/indices/create_index_stream.js b/src/es_archiver/lib/indices/create_index_stream.ts similarity index 81% rename from src/es_archiver/lib/indices/create_index_stream.js rename to src/es_archiver/lib/indices/create_index_stream.ts index 8fe4bc568cd231..df9d3bb623ad65 100644 --- a/src/es_archiver/lib/indices/create_index_stream.js +++ b/src/es_archiver/lib/indices/create_index_stream.ts @@ -17,13 +17,36 @@ * under the License. */ -import { Transform } from 'stream'; - +import { Transform, Readable } from 'stream'; import { get, once } from 'lodash'; +import { Client } from 'elasticsearch'; +import { ToolingLog } from '@kbn/dev-utils'; + +import { Stats } from '../stats'; import { deleteKibanaIndices } from './kibana_index'; import { deleteIndex } from './delete_index'; -export function createCreateIndexStream({ client, stats, skipExisting, log }) { +interface DocRecord { + value: { + index: string; + type: string; + settings: Record; + mappings: Record; + aliases: Record; + }; +} + +export function createCreateIndexStream({ + client, + stats, + skipExisting = false, + log, +}: { + client: Client; + stats: Stats; + skipExisting?: boolean; + log: ToolingLog; +}) { const skipDocsFromIndices = new Set(); // If we're trying to import Kibana index docs, we need to ensure that @@ -31,7 +54,7 @@ export function createCreateIndexStream({ client, stats, skipExisting, log }) { // migrations. This only needs to be done once per archive load operation. const deleteKibanaIndicesOnce = once(deleteKibanaIndices); - async function handleDoc(stream, record) { + async function handleDoc(stream: Readable, record: DocRecord) { if (skipDocsFromIndices.has(record.value.index)) { return; } @@ -39,7 +62,7 @@ export function createCreateIndexStream({ client, stats, skipExisting, log }) { stream.push(record); } - async function handleIndex(record) { + async function handleIndex(record: DocRecord) { const { index, settings, mappings, aliases } = record.value; const isKibana = index.startsWith('.kibana'); @@ -102,7 +125,7 @@ export function createCreateIndexStream({ client, stats, skipExisting, log }) { break; } - callback(null); + callback(); } catch (err) { callback(err); } diff --git a/src/es_archiver/lib/indices/delete_index.js b/src/es_archiver/lib/indices/delete_index.ts similarity index 76% rename from src/es_archiver/lib/indices/delete_index.js rename to src/es_archiver/lib/indices/delete_index.ts index 6f60d9533a36b3..e3fca587fbc3d3 100644 --- a/src/es_archiver/lib/indices/delete_index.js +++ b/src/es_archiver/lib/indices/delete_index.ts @@ -18,22 +18,34 @@ */ import { get } from 'lodash'; +import { Client } from 'elasticsearch'; +import { ToolingLog } from '@kbn/dev-utils'; +import { Stats } from '../stats'; // see https://github.com/elastic/elasticsearch/blob/99f88f15c5febbca2d13b5b5fda27b844153bf1a/server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java#L313-L319 const PENDING_SNAPSHOT_STATUSES = ['INIT', 'STARTED', 'WAITING']; -export async function deleteIndex(options) { +export async function deleteIndex(options: { + client: Client; + stats: Stats; + index: string; + log: ToolingLog; + retryIfSnapshottingCount?: number; +}): Promise { const { client, stats, index, log, retryIfSnapshottingCount = 10 } = options; const getIndicesToDelete = async () => { const aliasInfo = await client.indices.getAlias({ name: index, ignore: [404] }); - return aliasInfo.status === 404 ? index : Object.keys(aliasInfo); + return aliasInfo.status === 404 ? [index] : Object.keys(aliasInfo); }; try { const indicesToDelete = await getIndicesToDelete(); await client.indices.delete({ index: indicesToDelete }); - stats.deletedIndex(indicesToDelete); + for (let i = 0; i < indicesToDelete.length; i++) { + const indexToDelete = indicesToDelete[i]; + stats.deletedIndex(indexToDelete); + } } catch (error) { if (retryIfSnapshottingCount > 0 && isDeleteWhileSnapshotInProgressError(error)) { stats.waitingForInProgressSnapshot(index); @@ -56,7 +68,7 @@ export async function deleteIndex(options) { * @param {Error} error * @return {Boolean} */ -export function isDeleteWhileSnapshotInProgressError(error) { +export function isDeleteWhileSnapshotInProgressError(error: object) { return get(error, 'body.error.reason', '').startsWith( 'Cannot delete indices that are being snapshotted' ); @@ -65,13 +77,9 @@ export function isDeleteWhileSnapshotInProgressError(error) { /** * Wait for the any snapshot in any repository that is * snapshotting this index to complete. - * - * @param {EsClient} client - * @param {string} index the name of the index to look for - * @return {Promise} */ -export async function waitForSnapshotCompletion(client, index, log) { - const isSnapshotPending = async (repository, snapshot) => { +export async function waitForSnapshotCompletion(client: Client, index: string, log: ToolingLog) { + const isSnapshotPending = async (repository: string, snapshot: string) => { const { snapshots: [status], } = await client.snapshot.status({ @@ -83,7 +91,7 @@ export async function waitForSnapshotCompletion(client, index, log) { return PENDING_SNAPSHOT_STATUSES.includes(status.state); }; - const getInProgressSnapshots = async repository => { + const getInProgressSnapshots = async (repository: string) => { const { snapshots: inProgressSnapshots } = await client.snapshot.get({ repository, snapshot: '_current', @@ -91,9 +99,9 @@ export async function waitForSnapshotCompletion(client, index, log) { return inProgressSnapshots; }; - for (const repository of Object.keys(await client.snapshot.getRepository())) { + for (const repository of Object.keys(await client.snapshot.getRepository({} as any))) { const allInProgress = await getInProgressSnapshots(repository); - const found = allInProgress.find(s => s.indices.includes(index)); + const found = allInProgress.find((s: any) => s.indices.includes(index)); if (!found) { continue; diff --git a/src/es_archiver/lib/indices/delete_index_stream.js b/src/es_archiver/lib/indices/delete_index_stream.ts similarity index 86% rename from src/es_archiver/lib/indices/delete_index_stream.js rename to src/es_archiver/lib/indices/delete_index_stream.ts index 31a49ed30a124d..b4e1e530e1f84e 100644 --- a/src/es_archiver/lib/indices/delete_index_stream.js +++ b/src/es_archiver/lib/indices/delete_index_stream.ts @@ -18,11 +18,19 @@ */ import { Transform } from 'stream'; +import { Client } from 'elasticsearch'; +import { ToolingLog } from '@kbn/dev-utils'; +import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; import { cleanKibanaIndices } from './kibana_index'; -export function createDeleteIndexStream(client, stats, log, kibanaPluginIds) { +export function createDeleteIndexStream( + client: Client, + stats: Stats, + log: ToolingLog, + kibanaPluginIds: string[] +) { return new Transform({ readableObjectMode: true, writableObjectMode: true, diff --git a/src/es_archiver/lib/indices/generate_index_records_stream.js b/src/es_archiver/lib/indices/generate_index_records_stream.ts similarity index 89% rename from src/es_archiver/lib/indices/generate_index_records_stream.js rename to src/es_archiver/lib/indices/generate_index_records_stream.ts index 1d1a44aa634c24..b4b98f8ae262c7 100644 --- a/src/es_archiver/lib/indices/generate_index_records_stream.js +++ b/src/es_archiver/lib/indices/generate_index_records_stream.ts @@ -18,14 +18,16 @@ */ import { Transform } from 'stream'; +import { Client } from 'elasticsearch'; +import { Stats } from '../stats'; -export function createGenerateIndexRecordsStream(client, stats) { +export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { return new Transform({ writableObjectMode: true, readableObjectMode: true, async transform(indexOrAlias, enc, callback) { try { - const resp = await client.indices.get({ + const resp = (await client.indices.get({ index: indexOrAlias, filterPath: [ '*.settings', @@ -36,7 +38,7 @@ export function createGenerateIndexRecordsStream(client, stats) { '-*.settings.index.version', '-*.settings.index.provided_name', ], - }); + })) as Record; for (const [index, { settings, mappings }] of Object.entries(resp)) { const { diff --git a/src/es_archiver/lib/indices/index.js b/src/es_archiver/lib/indices/index.ts similarity index 100% rename from src/es_archiver/lib/indices/index.js rename to src/es_archiver/lib/indices/index.ts diff --git a/src/es_archiver/lib/indices/kibana_index.js b/src/es_archiver/lib/indices/kibana_index.ts similarity index 70% rename from src/es_archiver/lib/indices/kibana_index.js rename to src/es_archiver/lib/indices/kibana_index.ts index 744132bdcef69e..de67ba7c4e31ec 100644 --- a/src/es_archiver/lib/indices/kibana_index.js +++ b/src/es_archiver/lib/indices/kibana_index.ts @@ -17,29 +17,34 @@ * under the License. */ -import _ from 'lodash'; +import { get } from 'lodash'; import fs from 'fs'; -import path from 'path'; +import Path from 'path'; import { promisify } from 'util'; import { toArray } from 'rxjs/operators'; +import { Client, CreateDocumentParams } from 'elasticsearch'; +import { ToolingLog } from '@kbn/dev-utils'; +import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; -import { collectUiExports } from '../../../legacy/ui/ui_exports'; import { KibanaMigrator } from '../../../core/server/saved_objects/migrations'; import { SavedObjectsSchema } from '../../../core/server/saved_objects'; +// @ts-ignore +import { collectUiExports } from '../../../legacy/ui/ui_exports'; +// @ts-ignore import { findPluginSpecs } from '../../../legacy/plugin_discovery'; /** * Load the uiExports for a Kibana instance, only load uiExports from xpack if * it is enabled in the Kibana server. */ -const getUiExports = async kibanaPluginIds => { +const getUiExports = async (kibanaPluginIds: string[]) => { const xpackEnabled = kibanaPluginIds.includes('xpack_main'); const { spec$ } = await findPluginSpecs({ plugins: { - scanDirs: [path.resolve(__dirname, '../../../legacy/core_plugins')], - paths: xpackEnabled ? [path.resolve(__dirname, '../../../../x-pack')] : [], + scanDirs: [Path.resolve(__dirname, '../../../legacy/core_plugins')], + paths: xpackEnabled ? [Path.resolve(__dirname, '../../../../x-pack')] : [], }, }); @@ -50,7 +55,15 @@ const getUiExports = async kibanaPluginIds => { /** * Deletes all indices that start with `.kibana` */ -export async function deleteKibanaIndices({ client, stats, log }) { +export async function deleteKibanaIndices({ + client, + stats, + log, +}: { + client: Client; + stats: Stats; + log: ToolingLog; +}) { const indexNames = await fetchKibanaIndices(client); if (!indexNames.length) { return; @@ -76,37 +89,52 @@ export async function deleteKibanaIndices({ client, stats, log }) { * builds up an object that implements just enough of the kbnMigrations interface * as is required by migrations. */ -export async function migrateKibanaIndex({ client, log, kibanaPluginIds }) { +export async function migrateKibanaIndex({ + client, + log, + kibanaPluginIds, +}: { + client: Client; + log: ToolingLog; + kibanaPluginIds: string[]; +}) { const uiExports = await getUiExports(kibanaPluginIds); const kibanaVersion = await loadKibanaVersion(); - const config = { + const config: Record = { 'xpack.task_manager.index': '.kibana_task_manager', }; + const logger = { + trace: log.verbose.bind(log), + debug: log.debug.bind(log), + info: log.info.bind(log), + warn: log.warning.bind(log), + error: log.error.bind(log), + fatal: log.error.bind(log), + log: (entry: any) => log.info(entry.message), + get: () => logger, + }; + const migratorOptions = { - config: { get: path => config[path] }, + config: { get: (path: string) => config[path] } as any, savedObjectsConfig: { scrollDuration: '5m', batchSize: 100, pollInterval: 100, + skip: false, }, kibanaConfig: { index: '.kibana', - }, - logger: { - trace: log.verbose.bind(log), - debug: log.debug.bind(log), - info: log.info.bind(log), - warn: log.warning.bind(log), - error: log.error.bind(log), - }, - version: kibanaVersion, + } as any, + logger, + kibanaVersion, savedObjectSchemas: new SavedObjectsSchema(uiExports.savedObjectSchemas), savedObjectMappings: uiExports.savedObjectMappings, savedObjectMigrations: uiExports.savedObjectMigrations, savedObjectValidations: uiExports.savedObjectValidations, - callCluster: (path, ...args) => _.get(client, path).call(client, ...args), + callCluster: (path: string, ...args: any[]) => + (get(client, path) as Function).call(client, ...args), }; return await new KibanaMigrator(migratorOptions).runMigrations(); @@ -114,8 +142,8 @@ export async function migrateKibanaIndex({ client, log, kibanaPluginIds }) { async function loadKibanaVersion() { const readFile = promisify(fs.readFile); - const packageJson = await readFile(path.join(__dirname, '../../../../package.json')); - return JSON.parse(packageJson).version; + const packageJson = await readFile(Path.join(__dirname, '../../../../package.json')); + return JSON.parse(packageJson.toString('utf-8')).version; } /** @@ -123,16 +151,24 @@ async function loadKibanaVersion() { * .kibana, .kibana_1, .kibana_323, etc. This finds all indices starting * with .kibana, then filters out any that aren't actually Kibana's core * index (e.g. we don't want to remove .kibana_task_manager or the like). - * - * @param {string} index */ -async function fetchKibanaIndices(client) { +async function fetchKibanaIndices(client: Client) { const kibanaIndices = await client.cat.indices({ index: '.kibana*', format: 'json' }); - const isKibanaIndex = index => /^\.kibana(:?_\d*)?$/.test(index); - return kibanaIndices.map(x => x.index).filter(isKibanaIndex); + const isKibanaIndex = (index: string) => /^\.kibana(:?_\d*)?$/.test(index); + return kibanaIndices.map((x: { index: string }) => x.index).filter(isKibanaIndex); } -export async function cleanKibanaIndices({ client, stats, log, kibanaPluginIds }) { +export async function cleanKibanaIndices({ + client, + stats, + log, + kibanaPluginIds, +}: { + client: Client; + stats: Stats; + log: ToolingLog; + kibanaPluginIds: string[]; +}) { if (!kibanaPluginIds.includes('spaces')) { return await deleteKibanaIndices({ client, @@ -178,7 +214,7 @@ export async function cleanKibanaIndices({ client, stats, log, kibanaPluginIds } stats.deletedIndex('.kibana'); } -export async function createDefaultSpace({ index, client }) { +export async function createDefaultSpace({ index, client }: { index: string; client: Client }) { await client.create({ index, id: 'space:default', @@ -193,5 +229,5 @@ export async function createDefaultSpace({ index, client }) { _reserved: true, }, }, - }); + } as CreateDocumentParams); } diff --git a/src/es_archiver/lib/records/__tests__/filter_records_stream.js b/src/es_archiver/lib/records/__tests__/filter_records_stream.ts similarity index 97% rename from src/es_archiver/lib/records/__tests__/filter_records_stream.js rename to src/es_archiver/lib/records/__tests__/filter_records_stream.ts index fd35575ca59bae..d5830478decbae 100644 --- a/src/es_archiver/lib/records/__tests__/filter_records_stream.js +++ b/src/es_archiver/lib/records/__tests__/filter_records_stream.ts @@ -51,7 +51,7 @@ describe('esArchiver: createFilterRecordsStream()', () => { it('produces record values that have a matching type', async () => { const type1 = chance.word({ length: 5 }); - const output = await createPromiseFromStreams([ + const output = await createPromiseFromStreams([ createListStream([ { type: type1, value: {} }, { type: type1, value: {} }, diff --git a/src/es_archiver/lib/records/filter_records_stream.js b/src/es_archiver/lib/records/filter_records_stream.ts similarity index 91% rename from src/es_archiver/lib/records/filter_records_stream.js rename to src/es_archiver/lib/records/filter_records_stream.ts index 5a835ffe8e84d5..191cbd3b921e3b 100644 --- a/src/es_archiver/lib/records/filter_records_stream.js +++ b/src/es_archiver/lib/records/filter_records_stream.ts @@ -19,14 +19,14 @@ import { Transform } from 'stream'; -export function createFilterRecordsStream(type) { +export function createFilterRecordsStream(type: string) { return new Transform({ writableObjectMode: true, readableObjectMode: true, transform(record, enc, callback) { if (record && record.type === type) { - callback(null, record); + callback(undefined, record); } else { callback(); } diff --git a/src/es_archiver/lib/records/index.js b/src/es_archiver/lib/records/index.ts similarity index 100% rename from src/es_archiver/lib/records/index.js rename to src/es_archiver/lib/records/index.ts diff --git a/src/es_archiver/lib/stats.ts b/src/es_archiver/lib/stats.ts index 5f73304abf9a8b..c69b764fc72908 100644 --- a/src/es_archiver/lib/stats.ts +++ b/src/es_archiver/lib/stats.ts @@ -37,6 +37,8 @@ export interface IndexStats { }; } +export type Stats = ReturnType; + export function createStats(name: string, log: ToolingLog) { const info = (msg: string, ...args: any[]) => log.info(`[${name}] ${msg}`, ...args); const debug = (msg: string, ...args: any[]) => log.debug(`[${name}] ${msg}`, ...args); diff --git a/src/legacy/utils/index.d.ts b/src/legacy/utils/index.d.ts index a57caad1d34bf8..c294c79542bbe9 100644 --- a/src/legacy/utils/index.d.ts +++ b/src/legacy/utils/index.d.ts @@ -18,3 +18,16 @@ */ export function unset(object: object, rawPath: string): void; + +export { + concatStreamProviders, + createConcatStream, + createFilterStream, + createIntersperseStream, + createListStream, + createMapStream, + createPromiseFromStreams, + createReduceStream, + createReplaceStream, + createSplitStream, +} from './streams'; diff --git a/src/legacy/utils/streams/index.d.ts b/src/legacy/utils/streams/index.d.ts index b8d4c67050b2da..5ef39b292c6858 100644 --- a/src/legacy/utils/streams/index.d.ts +++ b/src/legacy/utils/streams/index.d.ts @@ -20,17 +20,17 @@ import { Readable, Transform, Writable, TransformOptions } from 'stream'; export function concatStreamProviders( - sourceProviders: Readable[], + sourceProviders: Array<() => Readable>, options: TransformOptions ): Transform; export function createIntersperseStream(intersperseChunk: string | Buffer): Transform; export function createSplitStream(splitChunk: T): Transform; -export function createListStream(items: any[]): Readable; +export function createListStream(items: any | any[]): Readable; export function createReduceStream(reducer: (value: any, chunk: T, enc: string) => T): Transform; export function createPromiseFromStreams([first, ...rest]: [Readable, ...Writable[]]): Promise< T >; -export function createConcatStream(initial: any): Transform; +export function createConcatStream(initial?: any): Transform; export function createMapStream(fn: (value: T, i: number) => void): Transform; export function createReplaceStream(toReplace: string, replacement: string | Buffer): Transform; export function createFilterStream(fn: (obj: T) => boolean): Transform; From 3d96e4c95bdc7ce2401b66fc1c816d826496382a Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Mon, 3 Feb 2020 13:24:38 +0100 Subject: [PATCH 57/69] [SIEM] Fix Welcome to SIEM typo (#56582) --- x-pack/legacy/plugins/siem/public/pages/common/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/siem/public/pages/common/translations.ts b/x-pack/legacy/plugins/siem/public/pages/common/translations.ts index 3e203383756163..072aee50d5136b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/common/translations.ts +++ b/x-pack/legacy/plugins/siem/public/pages/common/translations.ts @@ -12,7 +12,7 @@ export const EMPTY_TITLE = i18n.translate('xpack.siem.pages.common.emptyTitle', export const EMPTY_MESSAGE = i18n.translate('xpack.siem.pages.common.emptyMessage', { defaultMessage: - 'To begin using security information and event management, you’ll need to begin adding SIEM-related data to Kibana by installing and configuring our data shippers, called Beats. Let’s do that now!', + 'To begin using security information and event management (SIEM), you’ll need to add SIEM-related data, in Elastic Common Schema (ECS) format, to the Elastic Stack. An easy way to get started is by installing and configuring our data shippers, called Beats. Let’s do that now!', }); export const EMPTY_ACTION_PRIMARY = i18n.translate('xpack.siem.pages.common.emptyActionPrimary', { From 598968f20f1b3b09429dd6eac079b010913f0dee Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Mon, 3 Feb 2020 13:33:19 +0100 Subject: [PATCH 58/69] fix duplicate header warning (#56491) logged when attaching 2+ headers due to excessive check Co-authored-by: Elastic Machine --- src/core/server/http/integration_tests/lifecycle.test.ts | 1 + src/core/server/http/lifecycle/on_pre_response.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts index b16352838fad11..6dc7ece1359df7 100644 --- a/src/core/server/http/integration_tests/lifecycle.test.ts +++ b/src/core/server/http/integration_tests/lifecycle.test.ts @@ -721,6 +721,7 @@ describe('Auth', () => { res.ok({ headers: { 'www-authenticate': 'from handler', + 'another-header': 'yet another header', }, }) ); diff --git a/src/core/server/http/lifecycle/on_pre_response.ts b/src/core/server/http/lifecycle/on_pre_response.ts index 45d7478df98051..50d3d7b47bf8d6 100644 --- a/src/core/server/http/lifecycle/on_pre_response.ts +++ b/src/core/server/http/lifecycle/on_pre_response.ts @@ -120,8 +120,8 @@ export function adoptToHapiOnPreResponseFormat(fn: OnPreResponseHandler, log: Lo ...(result.headers as any), // hapi types don't specify string[] as valid value }; } else { + findHeadersIntersection(response.headers, result.headers, log); for (const [headerName, headerValue] of Object.entries(result.headers)) { - findHeadersIntersection(response.headers, result.headers, log); response.header(headerName, headerValue as any); // hapi types don't specify string[] as valid value } } From 8def60e1dac63ba7d7900bbffca6e1519ff1dfb7 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 3 Feb 2020 14:43:10 +0100 Subject: [PATCH 59/69] Unify Security and EncryptedSavedObjects public contract names according to NP migration guide. (#56597) --- .../plugins/alerting/server/alerts_client.ts | 6 +++--- .../alerting/server/alerts_client_factory.ts | 6 +++--- x-pack/legacy/plugins/alerting/server/shim.ts | 18 +++++++++--------- .../server/task_runner/task_runner_factory.ts | 4 ++-- .../plugins/encrypted_saved_objects/index.ts | 4 ++-- x-pack/legacy/plugins/reporting/index.ts | 2 +- .../legacy/plugins/reporting/server/plugin.ts | 2 +- x-pack/legacy/plugins/siem/server/plugin.ts | 4 ++-- .../actions/server/lib/action_executor.ts | 4 ++-- .../actions/server/lib/task_runner_factory.ts | 4 ++-- x-pack/plugins/actions/server/plugin.ts | 8 ++++---- x-pack/plugins/case/server/plugin.ts | 2 +- x-pack/plugins/case/server/services/index.ts | 5 +---- .../encrypted_saved_objects/server/index.ts | 2 +- .../encrypted_saved_objects/server/mocks.ts | 6 +++--- .../encrypted_saved_objects/server/plugin.ts | 6 +++--- x-pack/plugins/security/server/index.ts | 6 +++--- x-pack/plugins/security/server/mocks.ts | 4 ++-- x-pack/plugins/security/server/plugin.ts | 4 ++-- .../lib/spaces_client/spaces_client.test.ts | 8 ++++---- .../server/lib/spaces_client/spaces_client.ts | 6 +++--- x-pack/plugins/spaces/server/plugin.ts | 2 +- .../server/spaces_service/spaces_service.ts | 2 +- .../common/fixtures/plugins/aad/index.ts | 5 +++-- .../plugins/encrypted_saved_objects/index.ts | 9 +++++---- 25 files changed, 64 insertions(+), 65 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index a6ba936b76570e..1346d403edda1a 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -29,7 +29,7 @@ import { CreateAPIKeyResult as SecurityPluginCreateAPIKeyResult, InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult, } from '../../../../plugins/security/server'; -import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../plugins/encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../../plugins/encrypted_saved_objects/server'; import { TaskManagerStartContract } from '../../../../plugins/task_manager/server'; type NormalizedAlertAction = Omit; @@ -45,7 +45,7 @@ interface ConstructorOptions { taskManager: TaskManagerStartContract; savedObjectsClient: SavedObjectsClientContract; alertTypeRegistry: AlertTypeRegistry; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; spaceId?: string; namespace?: string; getUserName: () => Promise; @@ -120,7 +120,7 @@ export class AlertsClient { private readonly invalidateAPIKey: ( params: InvalidateAPIKeyParams ) => Promise; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; constructor({ alertTypeRegistry, diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client_factory.ts b/x-pack/legacy/plugins/alerting/server/alerts_client_factory.ts index eab1cc3ce627b4..de789fba0ac388 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client_factory.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client_factory.ts @@ -11,7 +11,7 @@ import { AlertTypeRegistry, SpaceIdToNamespaceFunction } from './types'; import { SecurityPluginStartContract } from './shim'; import { KibanaRequest, Logger } from '../../../../../src/core/server'; import { InvalidateAPIKeyParams } from '../../../../plugins/security/server'; -import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../plugins/encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../../plugins/encrypted_saved_objects/server'; import { TaskManagerStartContract } from '../../../../plugins/task_manager/server'; export interface ConstructorOpts { @@ -21,7 +21,7 @@ export interface ConstructorOpts { securityPluginSetup?: SecurityPluginStartContract; getSpaceId: (request: Hapi.Request) => string | undefined; spaceIdToNamespace: SpaceIdToNamespaceFunction; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; } export class AlertsClientFactory { @@ -31,7 +31,7 @@ export class AlertsClientFactory { private readonly securityPluginSetup?: SecurityPluginStartContract; private readonly getSpaceId: (request: Hapi.Request) => string | undefined; private readonly spaceIdToNamespace: SpaceIdToNamespaceFunction; - private readonly encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + private readonly encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; constructor(options: ConstructorOpts) { this.logger = options.logger; diff --git a/x-pack/legacy/plugins/alerting/server/shim.ts b/x-pack/legacy/plugins/alerting/server/shim.ts index 80d01ea722926f..bc8b0eb863634c 100644 --- a/x-pack/legacy/plugins/alerting/server/shim.ts +++ b/x-pack/legacy/plugins/alerting/server/shim.ts @@ -15,10 +15,10 @@ import { getTaskManagerSetup, getTaskManagerStart } from '../../task_manager/ser import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; import KbnServer from '../../../../../src/legacy/server/kbn_server'; import { - PluginSetupContract as EncryptedSavedObjectsSetupContract, - PluginStartContract as EncryptedSavedObjectsStartContract, + EncryptedSavedObjectsPluginSetup, + EncryptedSavedObjectsPluginStart, } from '../../../../plugins/encrypted_saved_objects/server'; -import { PluginSetupContract as SecurityPlugin } from '../../../../plugins/security/server'; +import { SecurityPluginSetup } from '../../../../plugins/security/server'; import { CoreSetup, LoggerFactory, @@ -44,8 +44,8 @@ export interface Server extends Legacy.Server { /** * Shim what we're thinking setup and start contracts will look like */ -export type SecurityPluginSetupContract = Pick; -export type SecurityPluginStartContract = Pick; +export type SecurityPluginSetupContract = Pick; +export type SecurityPluginStartContract = Pick; export type XPackMainPluginSetupContract = Pick; /** @@ -71,14 +71,14 @@ export interface AlertingPluginsSetup { taskManager: TaskManagerSetupContract; actions: ActionsPluginSetupContract; xpack_main: XPackMainPluginSetupContract; - encryptedSavedObjects: EncryptedSavedObjectsSetupContract; + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup; licensing: LicensingPluginSetup; } export interface AlertingPluginsStart { actions: ActionsPluginStartContract; security?: SecurityPluginStartContract; spaces: () => SpacesPluginStartContract | undefined; - encryptedSavedObjects: EncryptedSavedObjectsStartContract; + encryptedSavedObjects: EncryptedSavedObjectsPluginStart; taskManager: TaskManagerStartContract; } @@ -120,7 +120,7 @@ export function shim( actions: newPlatform.setup.plugins.actions as ActionsPluginSetupContract, xpack_main: server.plugins.xpack_main, encryptedSavedObjects: newPlatform.setup.plugins - .encryptedSavedObjects as EncryptedSavedObjectsSetupContract, + .encryptedSavedObjects as EncryptedSavedObjectsPluginSetup, licensing: newPlatform.setup.plugins.licensing as LicensingPluginSetup, }; @@ -131,7 +131,7 @@ export function shim( // initializes after this function is called spaces: () => server.plugins.spaces, encryptedSavedObjects: newPlatform.start.plugins - .encryptedSavedObjects as EncryptedSavedObjectsStartContract, + .encryptedSavedObjects as EncryptedSavedObjectsPluginStart, taskManager: getTaskManagerStart(server)!, }; diff --git a/x-pack/legacy/plugins/alerting/server/task_runner/task_runner_factory.ts b/x-pack/legacy/plugins/alerting/server/task_runner/task_runner_factory.ts index 67fef33b69c6dd..d2ecfb64c8a813 100644 --- a/x-pack/legacy/plugins/alerting/server/task_runner/task_runner_factory.ts +++ b/x-pack/legacy/plugins/alerting/server/task_runner/task_runner_factory.ts @@ -5,7 +5,7 @@ */ import { Logger } from '../../../../../../src/core/server'; import { RunContext } from '../../../../../plugins/task_manager/server'; -import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../../plugins/encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../../../plugins/encrypted_saved_objects/server'; import { PluginStartContract as ActionsPluginStartContract } from '../../../../../plugins/actions/server'; import { AlertType, @@ -19,7 +19,7 @@ export interface TaskRunnerContext { logger: Logger; getServices: GetServicesFunction; executeAction: ActionsPluginStartContract['execute']; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; spaceIdToNamespace: SpaceIdToNamespaceFunction; getBasePath: GetBasePathFunction; } diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts index 69058a7a33f59f..ce343dba006cfc 100644 --- a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts @@ -6,7 +6,7 @@ import { Root } from 'joi'; import { Legacy } from 'kibana'; -import { PluginSetupContract } from '../../../plugins/encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginSetup } from '../../../plugins/encrypted_saved_objects/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; @@ -29,7 +29,7 @@ export const encryptedSavedObjects = (kibana: { init(server: Legacy.Server) { const encryptedSavedObjectsPlugin = (server.newPlatform.setup.plugins - .encryptedSavedObjects as unknown) as PluginSetupContract; + .encryptedSavedObjects as unknown) as EncryptedSavedObjectsPluginSetup; if (!encryptedSavedObjectsPlugin) { throw new Error('New Platform XPack EncryptedSavedObjects plugin is not available.'); } diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts index d2a68e309a4b37..966e4ff209ad68 100644 --- a/x-pack/legacy/plugins/reporting/index.ts +++ b/x-pack/legacy/plugins/reporting/index.ts @@ -9,7 +9,7 @@ import { Legacy } from 'kibana'; import { IUiSettingsClient } from 'kibana/server'; import { resolve } from 'path'; import { PluginStart as DataPluginStart } from '../../../../src/plugins/data/server'; -import { PluginSetupContract as SecurityPluginSetup } from '../../../plugins/security/server'; +import { SecurityPluginSetup } from '../../../plugins/security/server'; import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants'; import { config as reportingConfig } from './config'; import { LegacySetup, ReportingPlugin, reportingPluginFactory } from './server/plugin'; diff --git a/x-pack/legacy/plugins/reporting/server/plugin.ts b/x-pack/legacy/plugins/reporting/server/plugin.ts index a2938d442f7df0..e618d23e8ed1f9 100644 --- a/x-pack/legacy/plugins/reporting/server/plugin.ts +++ b/x-pack/legacy/plugins/reporting/server/plugin.ts @@ -14,7 +14,7 @@ import { } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server'; -import { PluginSetupContract as SecurityPluginSetup } from '../../../../plugins/security/server'; +import { SecurityPluginSetup } from '../../../../plugins/security/server'; // @ts-ignore import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status'; import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; diff --git a/x-pack/legacy/plugins/siem/server/plugin.ts b/x-pack/legacy/plugins/siem/server/plugin.ts index 96eef2f44e5a06..94314367be59cf 100644 --- a/x-pack/legacy/plugins/siem/server/plugin.ts +++ b/x-pack/legacy/plugins/siem/server/plugin.ts @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, PluginInitializerContext, Logger } from 'src/core/server'; -import { PluginSetupContract as SecurityPlugin } from '../../../../plugins/security/server'; +import { SecurityPluginSetup } from '../../../../plugins/security/server'; import { PluginSetupContract as FeaturesSetupContract } from '../../../../plugins/features/server'; import { initServer } from './init_server'; import { compose } from './lib/compose/kibana'; @@ -17,7 +17,7 @@ import { ruleStatusSavedObjectType, } from './saved_objects'; -export type SiemPluginSecurity = Pick; +export type SiemPluginSecurity = Pick; export interface PluginsSetup { features: FeaturesSetupContract; diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index be6916a74fe88d..03a892a42792e2 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -12,7 +12,7 @@ import { GetServicesFunction, RawAction, } from '../types'; -import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server'; import { SpacesServiceSetup } from '../../../spaces/server'; import { EVENT_LOG_ACTIONS } from '../plugin'; import { IEvent, IEventLogger } from '../../../event_log/server'; @@ -21,7 +21,7 @@ export interface ActionExecutorContext { logger: Logger; spaces?: SpacesServiceSetup; getServices: GetServicesFunction; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; actionTypeRegistry: ActionTypeRegistryContract; eventLogger: IEventLogger; } diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index c3e89e0c16efcc..c78b43f4ef3ba3 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -8,12 +8,12 @@ import { ActionExecutorContract } from './action_executor'; import { ExecutorError } from './executor_error'; import { Logger, CoreStart } from '../../../../../src/core/server'; import { RunContext } from '../../../task_manager/server'; -import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server'; import { ActionTaskParams, GetBasePathFunction, SpaceIdToNamespaceFunction } from '../types'; export interface TaskRunnerContext { logger: Logger; - encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract; + encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart; spaceIdToNamespace: SpaceIdToNamespaceFunction; getBasePath: GetBasePathFunction; getScopedSavedObjectsClient: CoreStart['savedObjects']['getScopedClient']; diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index cb0e3347541fd7..dab09fc455ecf6 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -20,8 +20,8 @@ import { } from '../../../../src/core/server'; import { - PluginSetupContract as EncryptedSavedObjectsSetupContract, - PluginStartContract as EncryptedSavedObjectsStartContract, + EncryptedSavedObjectsPluginSetup, + EncryptedSavedObjectsPluginStart, } from '../../encrypted_saved_objects/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import { LicensingPluginSetup } from '../../licensing/server'; @@ -67,13 +67,13 @@ export interface PluginStartContract { export interface ActionsPluginsSetup { taskManager: TaskManagerSetupContract; - encryptedSavedObjects: EncryptedSavedObjectsSetupContract; + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup; licensing: LicensingPluginSetup; spaces?: SpacesPluginSetup; event_log: IEventLogService; } export interface ActionsPluginsStart { - encryptedSavedObjects: EncryptedSavedObjectsStartContract; + encryptedSavedObjects: EncryptedSavedObjectsPluginStart; taskManager: TaskManagerStartContract; } diff --git a/x-pack/plugins/case/server/plugin.ts b/x-pack/plugins/case/server/plugin.ts index c52461cade0586..37d087433a2ed1 100644 --- a/x-pack/plugins/case/server/plugin.ts +++ b/x-pack/plugins/case/server/plugin.ts @@ -9,7 +9,7 @@ import { CoreSetup, Logger, PluginInitializerContext } from 'kibana/server'; import { ConfigType } from './config'; import { initCaseApi } from './routes/api'; import { CaseService } from './services'; -import { PluginSetupContract as SecurityPluginSetup } from '../../security/server'; +import { SecurityPluginSetup } from '../../security/server'; function createConfig$(context: PluginInitializerContext) { return context.config.create().pipe(map(config => config)); diff --git a/x-pack/plugins/case/server/services/index.ts b/x-pack/plugins/case/server/services/index.ts index 684d905a5c71fe..531d5fa5b87e5b 100644 --- a/x-pack/plugins/case/server/services/index.ts +++ b/x-pack/plugins/case/server/services/index.ts @@ -21,10 +21,7 @@ import { UpdatedCaseType, UpdatedCommentType, } from '../routes/api/types'; -import { - AuthenticatedUser, - PluginSetupContract as SecurityPluginSetup, -} from '../../../security/server'; +import { AuthenticatedUser, SecurityPluginSetup } from '../../../security/server'; interface ClientArgs { client: SavedObjectsClientContract; diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.ts b/x-pack/plugins/encrypted_saved_objects/server/index.ts index 5e6edb95ec37a6..3b4b91de355c74 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/index.ts @@ -9,7 +9,7 @@ import { ConfigSchema } from './config'; import { Plugin } from './plugin'; export { EncryptedSavedObjectTypeRegistration, EncryptionError } from './crypto'; -export { PluginSetupContract, PluginStartContract } from './plugin'; +export { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin'; export const config = { schema: ConfigSchema }; export const plugin = (initializerContext: PluginInitializerContext) => diff --git a/x-pack/plugins/encrypted_saved_objects/server/mocks.ts b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts index 7f53f47760f129..13d7127db78353 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/mocks.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts @@ -4,21 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin'; function createEncryptedSavedObjectsSetupMock() { return { registerType: jest.fn(), __legacyCompat: { registerLegacyAPI: jest.fn() }, usingEphemeralEncryptionKey: true, - } as jest.Mocked; + } as jest.Mocked; } function createEncryptedSavedObjectsStartMock() { return { isEncryptionError: jest.fn(), getDecryptedAsInternalUser: jest.fn(), - } as jest.Mocked; + } as jest.Mocked; } export const encryptedSavedObjectsMock = { diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index d9185251ca4664..a0218c51c2723c 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -20,13 +20,13 @@ import { import { EncryptedSavedObjectsAuditLogger } from './audit'; import { SavedObjectsSetup, setupSavedObjects } from './saved_objects'; -export interface PluginSetupContract { +export interface EncryptedSavedObjectsPluginSetup { registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => void; __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => void }; usingEphemeralEncryptionKey: boolean; } -export interface PluginStartContract extends SavedObjectsSetup { +export interface EncryptedSavedObjectsPluginStart extends SavedObjectsSetup { isEncryptionError: (error: Error) => boolean; } @@ -59,7 +59,7 @@ export class Plugin { this.logger = this.initializerContext.logger.get(); } - public async setup(core: CoreSetup): Promise { + public async setup(core: CoreSetup): Promise { const { config, usingEphemeralEncryptionKey } = await createConfig$(this.initializerContext) .pipe(first()) .toPromise(); diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index 17e49b8cf40d30..c0e86b289fe545 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -12,7 +12,7 @@ import { RecursiveReadonly, } from '../../../../src/core/server'; import { ConfigSchema } from './config'; -import { Plugin, PluginSetupContract, PluginSetupDependencies } from './plugin'; +import { Plugin, SecurityPluginSetup, PluginSetupDependencies } from './plugin'; // These exports are part of public Security plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. @@ -24,7 +24,7 @@ export { InvalidateAPIKeyParams, InvalidateAPIKeyResult, } from './authentication'; -export { PluginSetupContract }; +export { SecurityPluginSetup }; export { AuthenticatedUser } from '../common/model'; export const config: PluginConfigDescriptor> = { @@ -35,7 +35,7 @@ export const config: PluginConfigDescriptor> = { ], }; export const plugin: PluginInitializer< - RecursiveReadonly, + RecursiveReadonly, void, PluginSetupDependencies > = (initializerContext: PluginInitializerContext) => new Plugin(initializerContext); diff --git a/x-pack/plugins/security/server/mocks.ts b/x-pack/plugins/security/server/mocks.ts index d5c08d5ab1ab94..ababf12c2be606 100644 --- a/x-pack/plugins/security/server/mocks.ts +++ b/x-pack/plugins/security/server/mocks.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginSetupContract } from './plugin'; +import { SecurityPluginSetup } from './plugin'; import { authenticationMock } from './authentication/index.mock'; import { authorizationMock } from './authorization/index.mock'; @@ -19,7 +19,7 @@ function createSetupMock() { mode: mockAuthz.mode, }, registerSpacesService: jest.fn(), - __legacyCompat: {} as PluginSetupContract['__legacyCompat'], + __legacyCompat: {} as SecurityPluginSetup['__legacyCompat'], }; } diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index ce682d8b30eb76..57644182347398 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -49,7 +49,7 @@ export interface LegacyAPI { /** * Describes public Security plugin contract returned at the `setup` stage. */ -export interface PluginSetupContract { +export interface SecurityPluginSetup { authc: Authentication; authz: Pick; @@ -166,7 +166,7 @@ export class Plugin { csp: core.http.csp, }); - return deepFreeze({ + return deepFreeze({ authc, authz: { diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts index 24a994e836e87d..74e75fb8f12c79 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginSetupContract as SecuritySetupContract } from '../../../../security/server'; +import { SecurityPluginSetup } from '../../../../security/server'; import { SpacesClient } from './spaces_client'; import { ConfigType, ConfigSchema } from '../../config'; import { GetSpacePurpose } from '../../../common/model/types'; @@ -224,17 +224,17 @@ describe('#getAll', () => { [ { purpose: undefined, - expectedPrivilege: (mockAuthorization: SecuritySetupContract['authz']) => + expectedPrivilege: (mockAuthorization: SecurityPluginSetup['authz']) => mockAuthorization.actions.login, }, { purpose: 'any', - expectedPrivilege: (mockAuthorization: SecuritySetupContract['authz']) => + expectedPrivilege: (mockAuthorization: SecurityPluginSetup['authz']) => mockAuthorization.actions.login, }, { purpose: 'copySavedObjectsIntoSpace', - expectedPrivilege: (mockAuthorization: SecuritySetupContract['authz']) => + expectedPrivilege: (mockAuthorization: SecurityPluginSetup['authz']) => mockAuthorization.actions.ui.get('savedObjectsManagement', 'copyIntoSpace'), }, ].forEach(scenario => { diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts index f964ae7d7ac32d..22c34c03368e36 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts @@ -6,7 +6,7 @@ import Boom from 'boom'; import { omit } from 'lodash'; import { KibanaRequest } from 'src/core/server'; -import { PluginSetupContract as SecurityPluginSetupContract } from '../../../../security/server'; +import { SecurityPluginSetup } from '../../../../security/server'; import { isReservedSpace } from '../../../common/is_reserved_space'; import { Space } from '../../../common/model/space'; import { SpacesAuditLogger } from '../audit_logger'; @@ -17,7 +17,7 @@ const SUPPORTED_GET_SPACE_PURPOSES: GetSpacePurpose[] = ['any', 'copySavedObject const PURPOSE_PRIVILEGE_MAP: Record< GetSpacePurpose, - (authorization: SecurityPluginSetupContract['authz']) => string + (authorization: SecurityPluginSetup['authz']) => string > = { any: authorization => authorization.actions.login, copySavedObjectsIntoSpace: authorization => @@ -28,7 +28,7 @@ export class SpacesClient { constructor( private readonly auditLogger: SpacesAuditLogger, private readonly debugLogger: (message: string) => void, - private readonly authorization: SecurityPluginSetupContract['authz'] | null, + private readonly authorization: SecurityPluginSetup['authz'] | null, private readonly callWithRequestSavedObjectRepository: any, private readonly config: ConfigType, private readonly internalSavedObjectRepository: any, diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index b8ef81c05f7aa4..52ff7eaee3d68c 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -14,7 +14,7 @@ import { PluginInitializerContext, } from '../../../../src/core/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; -import { PluginSetupContract as SecurityPluginSetup } from '../../security/server'; +import { SecurityPluginSetup } from '../../security/server'; import { LicensingPluginSetup } from '../../licensing/server'; import { XPackMainPlugin } from '../../../legacy/plugins/xpack_main/server/xpack_main'; import { createDefaultSpace } from './lib/create_default_space'; diff --git a/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts index f8ed58fa575518..95bda96d894615 100644 --- a/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts @@ -8,7 +8,7 @@ import { map, take } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; import { Legacy } from 'kibana'; import { Logger, KibanaRequest, CoreSetup } from '../../../../../src/core/server'; -import { PluginSetupContract as SecurityPluginSetup } from '../../../security/server'; +import { SecurityPluginSetup } from '../../../security/server'; import { LegacyAPI } from '../plugin'; import { SpacesClient } from '../lib/spaces_client'; import { ConfigType } from '../config'; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts index d7bee93f5c94b9..7194c642e7015e 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts @@ -8,7 +8,7 @@ import Joi from 'joi'; import Hapi from 'hapi'; import { Legacy } from 'kibana'; import KbnServer from '../../../../../../../src/legacy/server/kbn_server'; -import { PluginStartContract } from '../../../../../../plugins/encrypted_saved_objects/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../../../../plugins/encrypted_saved_objects/server'; interface CheckAADRequest extends Hapi.Request { payload: { @@ -25,7 +25,8 @@ export default function(kibana: any) { name: 'aad-fixtures', init(server: Legacy.Server) { const newPlatform = ((server as unknown) as KbnServer).newPlatform; - const esoPlugin = newPlatform.start.plugins.encryptedSavedObjects as PluginStartContract; + const esoPlugin = newPlatform.start.plugins + .encryptedSavedObjects as EncryptedSavedObjectsPluginStart; server.route({ method: 'POST', diff --git a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts index a194e477da7559..e61b8f24a1f69b 100644 --- a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts @@ -8,8 +8,8 @@ import { Request } from 'hapi'; import { boomify, badRequest } from 'boom'; import { Legacy } from 'kibana'; import { - PluginSetupContract, - PluginStartContract, + EncryptedSavedObjectsPluginSetup, + EncryptedSavedObjectsPluginStart, } from '../../../../plugins/encrypted_saved_objects/server'; const SAVED_OBJECT_WITH_SECRET_TYPE = 'saved-object-with-secret'; @@ -26,7 +26,7 @@ export default function esoPlugin(kibana: any) { path: '/api/saved_objects/get-decrypted-as-internal-user/{id}', async handler(request: Request) { const encryptedSavedObjectsStart = server.newPlatform.start.plugins - .encryptedSavedObjects as PluginStartContract; + .encryptedSavedObjects as EncryptedSavedObjectsPluginStart; const namespace = server.plugins.spaces && server.plugins.spaces.getSpaceId(request); try { return await encryptedSavedObjectsStart.getDecryptedAsInternalUser( @@ -44,7 +44,8 @@ export default function esoPlugin(kibana: any) { }, }); - (server.newPlatform.setup.plugins.encryptedSavedObjects as PluginSetupContract).registerType({ + (server.newPlatform.setup.plugins + .encryptedSavedObjects as EncryptedSavedObjectsPluginSetup).registerType({ type: SAVED_OBJECT_WITH_SECRET_TYPE, attributesToEncrypt: new Set(['privateProperty']), attributesToExcludeFromAAD: new Set(['publicPropertyExcludedFromAAD']), From f2713659f63fda25881e1c99087dc084cf4c85a1 Mon Sep 17 00:00:00 2001 From: Peter Pisljar Date: Mon, 3 Feb 2020 09:01:34 -0500 Subject: [PATCH 60/69] filtering (making it work with expressions) (#55351) * adding meta information to KibanaDatatable * updating filtering functions to use new information * moving filter creation to APPLY_FILTER_ACTION * adding SELECT_RANGE_ACTION and TRIGGER * making _meta optional * inlining legacy code for inspector * fixing jest tests * keeping apply_filter_action and adding value_click_action and trigger * utilities for serializing/unserializing aggConfigs * renaming prop to indexPatternId * cleanup * updating interpreter functional baselines * trying to fix tests * Fix legend tests * reverting update to multi metric screenshot * updating based on review * updating tests Co-authored-by: Nick Partridge Co-authored-by: Elastic Machine --- .../public/actions}/filters/brush_event.js | 14 +- .../actions}/filters/brush_event.test.js | 78 +++++++---- .../filters/brush_event.test.mocks.ts | 2 +- .../filters/create_filters_from_event.js} | 51 ++++--- .../public/actions/select_range_action.ts | 91 +++++++++++++ .../data/public/actions/value_click_action.ts | 126 ++++++++++++++++++ src/legacy/core_plugins/data/public/legacy.ts | 6 +- src/legacy/core_plugins/data/public/plugin.ts | 28 +++- .../build_tabular_inspector_data.ts | 4 +- .../search/expressions/create_filter.js | 66 +++++++++ .../data/public/search/expressions/esaggs.ts | 2 + .../data/public/search/expressions/utils.ts | 51 +++++++ .../core_plugins/data/public/search/index.ts | 1 + .../vislib/components/legend/legend.test.tsx | 58 ++++---- .../vislib/components/legend/legend.tsx | 60 +++++---- .../public/embeddable/visualize_embeddable.ts | 36 ++--- .../public/np_ready/public/filters/index.ts | 21 --- .../public/np_ready/public/index.ts | 3 - .../np_ready/public/types/base_vis_type.js | 10 -- src/legacy/ui/public/agg_types/agg_config.ts | 2 +- src/legacy/ui/public/agg_types/agg_types.ts | 92 +++++++++++++ src/legacy/ui/public/agg_types/index.ts | 80 +---------- .../ui/public/agg_types/param_types/field.ts | 4 +- src/legacy/ui/public/agg_types/utils.ts | 2 +- .../public/vis/lib/least_common_interval.ts | 2 +- src/plugins/embeddable/public/bootstrap.ts | 16 +++ src/plugins/embeddable/public/index.ts | 2 + .../embeddable/public/lib/triggers/index.ts | 2 + .../expression_types/kibana_datatable.ts | 7 + .../screenshots/baseline/combined_test.png | Bin 22801 -> 16994 bytes .../baseline/final_screenshot_test.png | Bin 22852 -> 17033 bytes .../screenshots/baseline/metric_all_data.png | Bin 32900 -> 24240 bytes .../baseline/metric_invalid_data.png | Bin 1920 -> 1806 bytes .../baseline/metric_percentage_mode.png | Bin 32587 -> 23705 bytes .../baseline/metric_single_metric_data.png | Bin 29643 -> 22004 bytes .../screenshots/baseline/partial_test_1.png | Bin 15140 -> 11228 bytes .../screenshots/baseline/partial_test_2.png | Bin 22801 -> 16994 bytes .../screenshots/baseline/partial_test_3.png | Bin 7049 -> 7054 bytes .../baseline/tagcloud_all_data.png | Bin 15701 -> 11827 bytes .../baseline/tagcloud_fontsize.png | Bin 13808 -> 10314 bytes .../baseline/tagcloud_invalid_data.png | Bin 1920 -> 1806 bytes .../baseline/tagcloud_metric_data.png | Bin 9163 -> 6712 bytes .../screenshots/baseline/tagcloud_options.png | Bin 18998 -> 15100 bytes .../snapshots/baseline/combined_test2.json | 2 +- .../snapshots/baseline/combined_test3.json | 2 +- .../snapshots/baseline/final_output_test.json | 2 +- .../snapshots/baseline/metric_all_data.json | 2 +- .../baseline/metric_multi_metric_data.json | 2 +- .../baseline/metric_percentage_mode.json | 2 +- .../baseline/metric_single_metric_data.json | 2 +- .../snapshots/baseline/partial_test_1.json | 2 +- .../snapshots/baseline/partial_test_2.json | 2 +- .../snapshots/baseline/partial_test_3.json | 2 +- .../snapshots/baseline/step_output_test2.json | 2 +- .../snapshots/baseline/step_output_test3.json | 2 +- .../snapshots/baseline/tagcloud_all_data.json | 2 +- .../snapshots/baseline/tagcloud_fontsize.json | 2 +- .../baseline/tagcloud_metric_data.json | 2 +- .../snapshots/baseline/tagcloud_options.json | 2 +- .../snapshots/session/combined_test2.json | 2 +- .../snapshots/session/combined_test3.json | 2 +- .../snapshots/session/final_output_test.json | 2 +- .../snapshots/session/metric_all_data.json | 2 +- .../session/metric_multi_metric_data.json | 2 +- .../session/metric_percentage_mode.json | 2 +- .../session/metric_single_metric_data.json | 2 +- .../snapshots/session/partial_test_1.json | 2 +- .../snapshots/session/partial_test_2.json | 2 +- .../snapshots/session/partial_test_3.json | 2 +- .../snapshots/session/step_output_test2.json | 2 +- .../snapshots/session/step_output_test3.json | 2 +- .../snapshots/session/tagcloud_all_data.json | 2 +- .../snapshots/session/tagcloud_fontsize.json | 2 +- .../session/tagcloud_metric_data.json | 2 +- .../snapshots/session/tagcloud_options.json | 2 +- 75 files changed, 700 insertions(+), 281 deletions(-) rename src/legacy/core_plugins/{visualizations/public/np_ready/public => data/public/actions}/filters/brush_event.js (81%) rename src/legacy/core_plugins/{visualizations/public/np_ready/public => data/public/actions}/filters/brush_event.test.js (71%) rename src/legacy/core_plugins/{visualizations/public/np_ready/public => data/public/actions}/filters/brush_event.test.mocks.ts (92%) rename src/legacy/core_plugins/{visualizations/public/np_ready/public/filters/vis_filters.js => data/public/actions/filters/create_filters_from_event.js} (72%) create mode 100644 src/legacy/core_plugins/data/public/actions/select_range_action.ts create mode 100644 src/legacy/core_plugins/data/public/actions/value_click_action.ts create mode 100644 src/legacy/core_plugins/data/public/search/expressions/create_filter.js create mode 100644 src/legacy/core_plugins/data/public/search/expressions/utils.ts delete mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/filters/index.ts create mode 100644 src/legacy/ui/public/agg_types/agg_types.ts diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.js similarity index 81% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.js rename to src/legacy/core_plugins/data/public/actions/filters/brush_event.js index e0854205b132ea..67711bd4599a2d 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.js +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.js @@ -19,9 +19,10 @@ import _ from 'lodash'; import moment from 'moment'; -import { esFilters } from '../../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../plugins/data/public'; +import { deserializeAggConfig } from '../../search/expressions/utils'; -export function onBrushEvent(event) { +export async function onBrushEvent(event, getIndexPatterns) { const isNumber = event.data.ordered; const isDate = isNumber && event.data.ordered.date; @@ -29,9 +30,12 @@ export function onBrushEvent(event) { if (!xRaw) return []; const column = xRaw.table.columns[xRaw.column]; if (!column) return []; - const aggConfig = event.aggConfigs[xRaw.column]; - if (!aggConfig) return []; - const indexPattern = aggConfig.getIndexPattern(); + if (!column.meta) return []; + const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); + const aggConfig = deserializeAggConfig({ + ...column.meta, + indexPattern, + }); const field = aggConfig.params.field; if (!field) return []; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js similarity index 71% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.js rename to src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js index 215d440edd9d02..a6fe58503cd021 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.js +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js @@ -20,21 +20,36 @@ import _ from 'lodash'; import moment from 'moment'; import expect from '@kbn/expect'; + +jest.mock('../../../../../ui/public/agg_types/agg_configs', () => ({ + AggConfigs: function AggConfigs() { + return { + createAggConfig: ({ params }) => ({ + params, + getIndexPattern: () => ({ + timeFieldName: 'time', + }), + }), + }; + }, +})); + import { onBrushEvent } from './brush_event'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; + const aggConfigs = [ + { + params: {}, + getIndexPattern: () => ({ + timeFieldName: 'time', + }), + }, + ]; + const baseEvent = { - aggConfigs: [ - { - params: {}, - getIndexPattern: () => ({ - timeFieldName: 'time', - }), - }, - ], data: { fieldFormatter: _.constant({}), series: [ @@ -47,6 +62,11 @@ describe('brushEvent', () => { columns: [ { id: '1', + meta: { + type: 'histogram', + indexPatternId: 'indexPatternId', + aggConfigParams: aggConfigs[0].params, + }, }, ], }, @@ -69,9 +89,11 @@ describe('brushEvent', () => { expect(onBrushEvent).to.be.a(Function); }); - test('ignores event when data.xAxisField not provided', () => { + test('ignores event when data.xAxisField not provided', async () => { const event = _.cloneDeep(baseEvent); - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: () => baseEvent.data.indexPattern, + })); expect(filters.length).to.equal(0); }); @@ -84,22 +106,26 @@ describe('brushEvent', () => { }; beforeEach(() => { + aggConfigs[0].params.field = dateField; dateEvent = _.cloneDeep(baseEvent); - dateEvent.aggConfigs[0].params.field = dateField; dateEvent.data.ordered = { date: true }; }); - test('by ignoring the event when range spans zero time', () => { + test('by ignoring the event when range spans zero time', async () => { const event = _.cloneDeep(dateEvent); event.range = [JAN_01_2014, JAN_01_2014]; - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: () => dateEvent.data.indexPattern, + })); expect(filters.length).to.equal(0); }); - test('by updating the timefilter', () => { + test('by updating the timefilter', async () => { const event = _.cloneDeep(dateEvent); event.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: async () => dateEvent.data.indexPattern, + })); expect(filters[0].range.time.gte).to.be(new Date(JAN_01_2014).toISOString()); // Set to a baseline timezone for comparison. expect(filters[0].range.time.lt).to.be(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); @@ -114,17 +140,19 @@ describe('brushEvent', () => { }; beforeEach(() => { + aggConfigs[0].params.field = dateField; dateEvent = _.cloneDeep(baseEvent); - dateEvent.aggConfigs[0].params.field = dateField; dateEvent.data.ordered = { date: true }; }); - test('creates a new range filter', () => { + test('creates a new range filter', async () => { const event = _.cloneDeep(dateEvent); const rangeBegin = JAN_01_2014; const rangeEnd = rangeBegin + DAY_IN_MS; event.range = [rangeBegin, rangeEnd]; - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: () => dateEvent.data.indexPattern, + })); expect(filters.length).to.equal(1); expect(filters[0].range.anotherTimeField.gte).to.equal(moment(rangeBegin).toISOString()); expect(filters[0].range.anotherTimeField.lt).to.equal(moment(rangeEnd).toISOString()); @@ -142,22 +170,26 @@ describe('brushEvent', () => { }; beforeEach(() => { + aggConfigs[0].params.field = numberField; numberEvent = _.cloneDeep(baseEvent); - numberEvent.aggConfigs[0].params.field = numberField; numberEvent.data.ordered = { date: false }; }); - test('by ignoring the event when range does not span at least 2 values', () => { + test('by ignoring the event when range does not span at least 2 values', async () => { const event = _.cloneDeep(numberEvent); event.range = [1]; - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: () => numberEvent.data.indexPattern, + })); expect(filters.length).to.equal(0); }); - test('by creating a new filter', () => { + test('by creating a new filter', async () => { const event = _.cloneDeep(numberEvent); event.range = [1, 2, 3, 4]; - const filters = onBrushEvent(event); + const filters = await onBrushEvent(event, () => ({ + get: () => numberEvent.data.indexPattern, + })); expect(filters.length).to.equal(1); expect(filters[0].range.numberField.gte).to.equal(1); expect(filters[0].range.numberField.lt).to.equal(4); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.mocks.ts b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.mocks.ts similarity index 92% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.mocks.ts rename to src/legacy/core_plugins/data/public/actions/filters/brush_event.test.mocks.ts index f0de2f88dcb82c..2cecfd0fe8b767 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/brush_event.test.mocks.ts +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.mocks.ts @@ -17,7 +17,7 @@ * under the License. */ -import { chromeServiceMock } from '../../../../../../../core/public/mocks'; +import { chromeServiceMock } from '../../../../../../core/public/mocks'; jest.doMock('ui/new_platform', () => ({ npStart: { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/vis_filters.js b/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.js similarity index 72% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/filters/vis_filters.js rename to src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.js index 303dec690e62bb..1037c718d0003f 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/vis_filters.js +++ b/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.js @@ -17,8 +17,10 @@ * under the License. */ -import { onBrushEvent } from './brush_event'; -import { esFilters } from '../../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../plugins/data/public'; +import { deserializeAggConfig } from '../../search/expressions/utils'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getIndexPatterns } from '../../../../../../plugins/data/public/services'; /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter @@ -63,11 +65,16 @@ const getOtherBucketFilterTerms = (table, columnIndex, rowIndex) => { * @param {string} cellValue - value of the current cell * @return {array|string} - filter or list of filters to provide to queryFilter.addFilters() */ -const createFilter = (aggConfigs, table, columnIndex, rowIndex, cellValue) => { +const createFilter = async (table, columnIndex, rowIndex) => { + if (!table || !table.columns || !table.columns[columnIndex]) return; const column = table.columns[columnIndex]; - const aggConfig = aggConfigs[columnIndex]; + const aggConfig = deserializeAggConfig({ + type: column.meta.type, + aggConfigParams: column.meta.aggConfigParams, + indexPattern: await getIndexPatterns().get(column.meta.indexPatternId), + }); let filter = []; - const value = rowIndex > -1 ? table.rows[rowIndex][column.id] : cellValue; + const value = rowIndex > -1 ? table.rows[rowIndex][column.id] : null; if (value === null || value === undefined || !aggConfig.isFilterable()) { return; } @@ -85,26 +92,28 @@ const createFilter = (aggConfigs, table, columnIndex, rowIndex, cellValue) => { return filter; }; -const createFiltersFromEvent = event => { +const createFiltersFromEvent = async event => { const filters = []; const dataPoints = event.data || [event]; - dataPoints - .filter(point => point) - .forEach(val => { - const { table, column, row, value } = val; - const filter = createFilter(event.aggConfigs, table, column, row, value); - if (filter) { - filter.forEach(f => { - if (event.negate) { - f = esFilters.toggleFilterNegated(f); - } - filters.push(f); - }); - } - }); + await Promise.all( + dataPoints + .filter(point => point) + .map(async val => { + const { table, column, row } = val; + const filter = await createFilter(table, column, row); + if (filter) { + filter.forEach(f => { + if (event.negate) { + f = esFilters.toggleFilterNegated(f); + } + filters.push(f); + }); + } + }) + ); return filters; }; -export { createFilter, createFiltersFromEvent, onBrushEvent }; +export { createFilter, createFiltersFromEvent }; diff --git a/src/legacy/core_plugins/data/public/actions/select_range_action.ts b/src/legacy/core_plugins/data/public/actions/select_range_action.ts new file mode 100644 index 00000000000000..4ea5c78a9fd2b4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/actions/select_range_action.ts @@ -0,0 +1,91 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { + IAction, + createAction, + IncompatibleActionError, +} from '../../../../../plugins/ui_actions/public'; +// @ts-ignore +import { onBrushEvent } from './filters/brush_event'; +import { + esFilters, + FilterManager, + TimefilterContract, + changeTimeFilter, + extractTimeFilter, + mapAndFlattenFilters, +} from '../../../../../plugins/data/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getIndexPatterns } from '../../../../../plugins/data/public/services'; + +export const SELECT_RANGE_ACTION = 'SELECT_RANGE_ACTION'; + +interface ActionContext { + data: any; + timeFieldName: string; +} + +async function isCompatible(context: ActionContext) { + try { + const filters: esFilters.Filter[] = (await onBrushEvent(context.data, getIndexPatterns)) || []; + return filters.length > 0; + } catch { + return false; + } +} + +export function selectRangeAction( + filterManager: FilterManager, + timeFilter: TimefilterContract +): IAction { + return createAction({ + type: SELECT_RANGE_ACTION, + id: SELECT_RANGE_ACTION, + getDisplayName: () => { + return i18n.translate('data.filter.applyFilterActionTitle', { + defaultMessage: 'Apply filter to current view', + }); + }, + isCompatible, + execute: async ({ timeFieldName, data }: ActionContext) => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + const filters: esFilters.Filter[] = (await onBrushEvent(data, getIndexPatterns)) || []; + + const selectedFilters: esFilters.Filter[] = mapAndFlattenFilters(filters); + + if (timeFieldName) { + const { timeRangeFilter, restOfFilters } = extractTimeFilter( + timeFieldName, + selectedFilters + ); + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + changeTimeFilter(timeFilter, timeRangeFilter); + } + } else { + filterManager.addFilters(selectedFilters); + } + }, + }); +} diff --git a/src/legacy/core_plugins/data/public/actions/value_click_action.ts b/src/legacy/core_plugins/data/public/actions/value_click_action.ts new file mode 100644 index 00000000000000..2f622eb1eb6695 --- /dev/null +++ b/src/legacy/core_plugins/data/public/actions/value_click_action.ts @@ -0,0 +1,126 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '../../../../../plugins/kibana_react/public'; +import { + IAction, + createAction, + IncompatibleActionError, +} from '../../../../../plugins/ui_actions/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getOverlays, getIndexPatterns } from '../../../../../plugins/data/public/services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { applyFiltersPopover } from '../../../../../plugins/data/public/ui/apply_filters'; +// @ts-ignore +import { createFiltersFromEvent } from './filters/create_filters_from_event'; +import { + esFilters, + FilterManager, + TimefilterContract, + changeTimeFilter, + extractTimeFilter, + mapAndFlattenFilters, +} from '../../../../../plugins/data/public'; + +export const VALUE_CLICK_ACTION = 'VALUE_CLICK_ACTION'; + +interface ActionContext { + data: any; + timeFieldName: string; +} + +async function isCompatible(context: ActionContext) { + try { + const filters: esFilters.Filter[] = (await createFiltersFromEvent(context.data)) || []; + return filters.length > 0; + } catch { + return false; + } +} + +export function valueClickAction( + filterManager: FilterManager, + timeFilter: TimefilterContract +): IAction { + return createAction({ + type: VALUE_CLICK_ACTION, + id: VALUE_CLICK_ACTION, + getDisplayName: () => { + return i18n.translate('data.filter.applyFilterActionTitle', { + defaultMessage: 'Apply filter to current view', + }); + }, + isCompatible, + execute: async ({ timeFieldName, data }: ActionContext) => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + const filters: esFilters.Filter[] = (await createFiltersFromEvent(data)) || []; + + let selectedFilters: esFilters.Filter[] = mapAndFlattenFilters(filters); + + if (selectedFilters.length > 1) { + const indexPatterns = await Promise.all( + filters.map(filter => { + return getIndexPatterns().get(filter.meta.index!); + }) + ); + + const filterSelectionPromise: Promise = new Promise(resolve => { + const overlay = getOverlays().openModal( + toMountPoint( + applyFiltersPopover( + filters, + indexPatterns, + () => { + overlay.close(); + resolve([]); + }, + (filterSelection: esFilters.Filter[]) => { + overlay.close(); + resolve(filterSelection); + } + ) + ), + { + 'data-test-subj': 'selectFilterOverlay', + } + ); + }); + + selectedFilters = await filterSelectionPromise; + } + + if (timeFieldName) { + const { timeRangeFilter, restOfFilters } = extractTimeFilter( + timeFieldName, + selectedFilters + ); + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + changeTimeFilter(timeFilter, timeRangeFilter); + } + } else { + filterManager.addFilters(selectedFilters); + } + }, + }); +} diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index a6646ea338c93c..d37c17c2240727 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -39,8 +39,6 @@ import { plugin } from '.'; const dataPlugin = plugin(); -export const setup = dataPlugin.setup(npSetup.core); +export const setup = dataPlugin.setup(npSetup.core, npSetup.plugins); -export const start = dataPlugin.start(npStart.core, { - data: npStart.plugins.data, -}); +export const start = dataPlugin.start(npStart.core, npStart.plugins); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 6bd85ef020f167..da35366cdff318 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -22,6 +22,7 @@ import { DataPublicPluginStart, addSearchStrategy, defaultSearchStrategy, + DataPublicPluginSetup, } from '../../../../plugins/data/public'; import { ExpressionsSetup } from '../../../../plugins/expressions/public'; @@ -32,15 +33,27 @@ import { setInjectedMetadata, setFieldFormats, setSearchService, + setOverlays, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../../plugins/data/public/services'; +import { SELECT_RANGE_ACTION, selectRangeAction } from './actions/select_range_action'; +import { VALUE_CLICK_ACTION, valueClickAction } from './actions/value_click_action'; +import { + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../plugins/embeddable/public/lib/triggers'; +import { IUiActionsSetup, IUiActionsStart } from '../../../../plugins/ui_actions/public'; export interface DataPluginSetupDependencies { + data: DataPublicPluginSetup; expressions: ExpressionsSetup; + uiActions: IUiActionsSetup; } export interface DataPluginStartDependencies { data: DataPublicPluginStart; + uiActions: IUiActionsStart; } /** @@ -64,19 +77,30 @@ export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty export class DataPlugin implements Plugin { - public setup(core: CoreSetup) { + public setup(core: CoreSetup, { data, uiActions }: DataPluginSetupDependencies) { setInjectedMetadata(core.injectedMetadata); // This is to be deprecated once we switch to the new search service fully addSearchStrategy(defaultSearchStrategy); + + uiActions.registerAction( + selectRangeAction(data.query.filterManager, data.query.timefilter.timefilter) + ); + uiActions.registerAction( + valueClickAction(data.query.filterManager, data.query.timefilter.timefilter) + ); } - public start(core: CoreStart, { data }: DataPluginStartDependencies): DataStart { + public start(core: CoreStart, { data, uiActions }: DataPluginStartDependencies): DataStart { setUiSettings(core.uiSettings); setQueryService(data.query); setIndexPatterns(data.indexPatterns); setFieldFormats(data.fieldFormats); setSearchService(data.search); + setOverlays(core.overlays); + + uiActions.attachAction(SELECT_RANGE_TRIGGER, SELECT_RANGE_ACTION); + uiActions.attachAction(VALUE_CLICK_TRIGGER, VALUE_CLICK_ACTION); return {}; } diff --git a/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts b/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts index 6e6d2a15fa2ac8..8f7953c408a971 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts @@ -19,9 +19,9 @@ import { set } from 'lodash'; // @ts-ignore -import { createFilter } from '../../../../visualizations/public'; import { FormattedData } from '../../../../../../plugins/inspector/public'; - +// @ts-ignore +import { createFilter } from './create_filter'; interface Column { id: string; name: string; diff --git a/src/legacy/core_plugins/data/public/search/expressions/create_filter.js b/src/legacy/core_plugins/data/public/search/expressions/create_filter.js new file mode 100644 index 00000000000000..3f4028a9b5525b --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/expressions/create_filter.js @@ -0,0 +1,66 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const getOtherBucketFilterTerms = (table, columnIndex, rowIndex) => { + if (rowIndex === -1) { + return []; + } + + // get only rows where cell value matches current row for all the fields before columnIndex + const rows = table.rows.filter(row => { + return table.columns.every((column, i) => { + return row[column.id] === table.rows[rowIndex][column.id] || i >= columnIndex; + }); + }); + const terms = rows.map(row => row[table.columns[columnIndex].id]); + + return [ + ...new Set( + terms.filter(term => { + const notOther = term !== '__other__'; + const notMissing = term !== '__missing__'; + return notOther && notMissing; + }) + ), + ]; +}; + +const createFilter = (aggConfigs, table, columnIndex, rowIndex, cellValue) => { + const column = table.columns[columnIndex]; + const aggConfig = aggConfigs[columnIndex]; + let filter = []; + const value = rowIndex > -1 ? table.rows[rowIndex][column.id] : cellValue; + if (value === null || value === undefined || !aggConfig.isFilterable()) { + return; + } + if (aggConfig.type.name === 'terms' && aggConfig.params.otherBucket) { + const terms = getOtherBucketFilterTerms(table, columnIndex, rowIndex); + filter = aggConfig.createFilter(value, { terms }); + } else { + filter = aggConfig.createFilter(value); + } + + if (!Array.isArray(filter)) { + filter = [filter]; + } + + return filter; +}; + +export { createFilter }; diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index 143283152d1044..b4ea2cd378d61b 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -46,6 +46,7 @@ import { Adapters } from '../../../../../../plugins/inspector/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { getQueryService, getIndexPatterns } from '../../../../../../plugins/data/public/services'; import { getRequestInspectorStats, getResponseInspectorStats } from '../..'; +import { serializeAggConfig } from './utils'; export interface RequestHandlerParams { searchSource: ISearchSource; @@ -289,6 +290,7 @@ export const esaggs = (): ExpressionFunction { + return { + type: aggConfig.type.name, + indexPatternId: aggConfig.getIndexPattern().id, + aggConfigParams: aggConfig.toJSON().params, + }; +}; + +interface DeserializeAggConfigParams { + type: string; + aggConfigParams: Record; + indexPattern: IndexPattern; +} + +export const deserializeAggConfig = ({ + type, + aggConfigParams, + indexPattern, +}: DeserializeAggConfigParams) => { + const aggConfigs = new AggConfigs(indexPattern); + const aggConfig = aggConfigs.createAggConfig({ + enabled: true, + type, + params: aggConfigParams, + }); + return aggConfig; +}; diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts index e1c93ec0e3b1c4..c975d5772e0a8b 100644 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ b/src/legacy/core_plugins/data/public/search/index.ts @@ -18,3 +18,4 @@ */ export { getRequestInspectorStats, getResponseInspectorStats } from './utils'; +export { serializeAggConfig } from './expressions/utils'; diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index 6f0a5a3784b070..e66dff01b6bf21 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -34,8 +34,8 @@ jest.mock('@elastic/eui', () => ({ jest.mock('../../../legacy_imports', () => ({ getTableAggs: jest.fn(), })); -jest.mock('../../../../../visualizations/public', () => ({ - createFiltersFromEvent: jest.fn().mockReturnValue(['yes']), +jest.mock('../../../../../data/public/actions/filters/create_filters_from_event', () => ({ + createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), })); const vis = { @@ -95,8 +95,8 @@ const uiState = { setSilent: jest.fn(), }; -const getWrapper = (props?: Partial) => - mount( +const getWrapper = async (props?: Partial) => { + const wrapper = mount( ) => ); + await (wrapper.find(VisLegend).instance() as VisLegend).refresh(); + wrapper.update(); + return wrapper; +}; + const getLegendItems = (wrapper: ReactWrapper) => wrapper.find('.visLegend__button'); describe('VisLegend Component', () => { @@ -120,9 +125,9 @@ describe('VisLegend Component', () => { }); describe('Legend open', () => { - beforeEach(() => { + beforeEach(async () => { mockState.set('vis.legendOpen', true); - wrapper = getWrapper(); + wrapper = await getWrapper(); }); it('should match the snapshot', () => { @@ -131,9 +136,9 @@ describe('VisLegend Component', () => { }); describe('Legend closed', () => { - beforeEach(() => { + beforeEach(async () => { mockState.set('vis.legendOpen', false); - wrapper = getWrapper(); + wrapper = await getWrapper(); }); it('should match the snapshot', () => { @@ -142,25 +147,26 @@ describe('VisLegend Component', () => { }); describe('Highlighting', () => { - beforeEach(() => { - wrapper = getWrapper(); + beforeEach(async () => { + wrapper = await getWrapper(); }); - it('should call highlight handler when legend item is focused', () => { + it('should call highlight handler when legend item is focused', async () => { const first = getLegendItems(wrapper).first(); + first.simulate('focus'); expect(vislibVis.handler.highlight).toHaveBeenCalledTimes(1); }); - it('should call highlight handler when legend item is hovered', () => { + it('should call highlight handler when legend item is hovered', async () => { const first = getLegendItems(wrapper).first(); first.simulate('mouseEnter'); expect(vislibVis.handler.highlight).toHaveBeenCalledTimes(1); }); - it('should call unHighlight handler when legend item is blurred', () => { + it('should call unHighlight handler when legend item is blurred', async () => { let first = getLegendItems(wrapper).first(); first.simulate('focus'); first = getLegendItems(wrapper).first(); @@ -169,7 +175,7 @@ describe('VisLegend Component', () => { expect(vislibVis.handler.unHighlight).toHaveBeenCalledTimes(1); }); - it('should call unHighlight handler when legend item is unhovered', () => { + it('should call unHighlight handler when legend item is unhovered', async () => { const first = getLegendItems(wrapper).first(); first.simulate('mouseEnter'); @@ -187,8 +193,8 @@ describe('VisLegend Component', () => { }, }; - expect(() => { - wrapper = getWrapper({ vis: newVis }); + expect(async () => { + wrapper = await getWrapper({ vis: newVis }); const first = getLegendItems(wrapper).first(); first.simulate('focus'); first.simulate('blur'); @@ -197,8 +203,8 @@ describe('VisLegend Component', () => { }); describe('Filtering', () => { - beforeEach(() => { - wrapper = getWrapper(); + beforeEach(async () => { + wrapper = await getWrapper(); }); it('should filter out when clicked', () => { @@ -223,8 +229,8 @@ describe('VisLegend Component', () => { }); describe('Toggles details', () => { - beforeEach(() => { - wrapper = getWrapper(); + beforeEach(async () => { + wrapper = await getWrapper(); }); it('should show details when clicked', () => { @@ -236,8 +242,8 @@ describe('VisLegend Component', () => { }); describe('setColor', () => { - beforeEach(() => { - wrapper = getWrapper(); + beforeEach(async () => { + wrapper = await getWrapper(); }); it('sets the color in the UI state', () => { @@ -255,18 +261,18 @@ describe('VisLegend Component', () => { }); describe('toggleLegend function', () => { - it('click should show legend once toggled from hidden', () => { + it('click should show legend once toggled from hidden', async () => { mockState.set('vis.legendOpen', false); - wrapper = getWrapper(); + wrapper = await getWrapper(); const toggleButton = wrapper.find('.visLegend__toggle').first(); toggleButton.simulate('click'); expect(wrapper.exists('.visLegend__list')).toBe(true); }); - it('click should hide legend once toggled from shown', () => { + it('click should hide legend once toggled from shown', async () => { mockState.set('vis.legendOpen', true); - wrapper = getWrapper(); + wrapper = await getWrapper(); const toggleButton = wrapper.find('.visLegend__toggle').first(); toggleButton.simulate('click'); diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index 0eec557dd334ee..a170af33583df0 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -24,7 +24,8 @@ import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keyCodes, htmlIdGenerator } from '@elastic/eui'; // @ts-ignore -import { createFiltersFromEvent } from '../../../../../visualizations/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { createFiltersFromEvent } from '../../../../../data/public/actions/filters/create_filters_from_event'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; import { VisLegendItem } from './legend_item'; import { getPieNames } from './pie_utils'; @@ -94,11 +95,11 @@ export class VisLegend extends PureComponent { this.props.vis.API.events.filter({ data, negate }); }; - canFilter = (item: LegendItem): boolean => { + canFilter = async (item: LegendItem): Promise => { if (CUSTOM_LEGEND_VIS_TYPES.includes(this.props.vislibVis.visConfigArgs.type)) { return false; } - const filters = createFiltersFromEvent({ aggConfigs: this.state.tableAggs, data: item.values }); + const filters = await createFiltersFromEvent({ data: item.values }); return Boolean(filters.length); }; @@ -123,16 +124,39 @@ export class VisLegend extends PureComponent { }; // Most of these functions were moved directly from the old Legend class. Not a fan of this. - getLabels = (data: any, type: string) => { - if (!data) return []; - data = data.columns || data.rows || [data]; + setLabels = (data: any, type: string): Promise => + new Promise(async resolve => { + let labels = []; + if (CUSTOM_LEGEND_VIS_TYPES.includes(type)) { + const legendLabels = this.props.vislibVis.getLegendLabels(); + if (legendLabels) { + labels = map(legendLabels, label => { + return { label }; + }); + } + } else { + if (!data) return []; + data = data.columns || data.rows || [data]; - if (type === 'pie') return getPieNames(data); + labels = type === 'pie' ? getPieNames(data) : this.getSeriesLabels(data); + } - return this.getSeriesLabels(data); - }; + const labelsConfig = await Promise.all( + labels.map(async label => ({ + ...label, + canFilter: await this.canFilter(label), + })) + ); + + this.setState( + { + labels: labelsConfig, + }, + resolve + ); + }); - refresh = () => { + refresh = async () => { const vislibVis = this.props.vislibVis; if (!vislibVis || !vislibVis.visConfig) { this.setState({ @@ -154,24 +178,12 @@ export class VisLegend extends PureComponent { this.setState({ open: this.props.vis.params.addLegend }); } - if (CUSTOM_LEGEND_VIS_TYPES.includes(vislibVis.visConfigArgs.type)) { - const legendLabels = this.props.vislibVis.getLegendLabels(); - if (legendLabels) { - this.setState({ - labels: map(legendLabels, label => { - return { label }; - }), - }); - } - } else { - this.setState({ labels: this.getLabels(this.props.visData, vislibVis.visConfigArgs.type) }); - } - if (vislibVis.visConfig) { this.getColor = this.props.vislibVis.visConfig.data.getColorFunc(); } this.setState({ tableAggs: getTableAggs(this.props.vis) }); + await this.setLabels(this.props.visData, vislibVis.visConfigArgs.type); }; highlight = (event: BaseSyntheticEvent) => { @@ -219,7 +231,7 @@ export class VisLegend extends PureComponent { key={item.label} anchorPosition={anchorPosition} selected={this.state.selectedLabel === item.label} - canFilter={this.canFilter(item)} + canFilter={item.canFilter} onFilter={this.filter} onSelect={this.toggleDetails} legendId={this.legendId} diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts index 2af468ff77de6e..d3badcc6bdc3fc 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -17,13 +17,12 @@ * under the License. */ -import _, { forEach } from 'lodash'; +import _ from 'lodash'; import { PersistedState } from 'ui/persisted_state'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; import { buildPipeline } from 'ui/visualize/loader/pipeline_helpers'; import { SavedObject } from 'ui/saved_objects/types'; -import { getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { AppState } from 'ui/state_management/app_state'; import { npStart } from 'ui/new_platform'; import { IExpressionLoaderParams } from 'src/plugins/expressions/public'; @@ -34,7 +33,6 @@ import { Query, onlyDisabledFiltersChanged, esFilters, - mapAndFlattenFilters, ISearchSource, } from '../../../../../plugins/data/public'; import { @@ -42,7 +40,8 @@ import { EmbeddableOutput, Embeddable, Container, - APPLY_FILTER_TRIGGER, + VALUE_CLICK_TRIGGER, + SELECT_RANGE_TRIGGER, } from '../../../../../plugins/embeddable/public'; import { dispatchRenderComplete } from '../../../../../plugins/kibana_utils/public'; import { SavedSearch } from '../../../kibana/public/discover/np_ready/types'; @@ -105,7 +104,6 @@ export class VisualizeEmbeddable extends Embeddable { - if (event.disabled || !eventName) { - return; - } else { - this.actions[eventName] = event.defaultAction; - } - }); - // This is a hack to give maps visualizations access to data in the // globalState, since they can no longer access it via searchSource. // TODO: Remove this as a part of elastic/kibana#30593 @@ -301,18 +290,13 @@ export class VisualizeEmbeddable extends Embeddable { - if (this.actions[event.name]) { - event.data.aggConfigs = getTableAggs(this.vis); - const filters: esFilters.Filter[] = this.actions[event.name](event.data) || []; - const mappedFilters = mapAndFlattenFilters(filters); - const timeFieldName = this.vis.indexPattern.timeFieldName; - - npStart.plugins.uiActions.executeTriggerActions(APPLY_FILTER_TRIGGER, { - embeddable: this, - filters: mappedFilters, - timeFieldName, - }); - } + const eventName = event.name === 'brush' ? SELECT_RANGE_TRIGGER : VALUE_CLICK_TRIGGER; + + npStart.plugins.uiActions.executeTriggerActions(eventName, { + embeddable: this, + timeFieldName: this.vis.indexPattern.timeFieldName, + data: event.data, + }); }) ); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/index.ts deleted file mode 100644 index 4558621dc6615a..00000000000000 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/filters/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// @ts-ignore -export * from './vis_filters'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index 4dffcb8ce995e3..3c4a1c1449d475 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -44,7 +44,6 @@ export function plugin(initializerContext: PluginInitializerContext) { /** @public static code */ export { Vis, VisParams, VisState } from './vis'; -export * from './filters'; export { TypesService } from './types/types_service'; export { Status } from './legacy/update_status'; @@ -53,6 +52,4 @@ export { buildPipeline, buildVislibDimensions, SchemaConfig } from './legacy/bui // @ts-ignore export { updateOldState } from './legacy/vis_update_state'; export { calculateObjectHash } from './legacy/calculate_object_hash'; -// @ts-ignore -export { createFiltersFromEvent } from './filters/vis_filters'; export { createSavedVisLoader } from '../../saved_visualizations/saved_visualizations'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js index f62b3a0b393aca..351acc48e26766 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js @@ -19,7 +19,6 @@ import _ from 'lodash'; -import { createFiltersFromEvent, onBrushEvent } from '../filters'; import { DefaultEditorController } from '../../../../../vis_default_editor/public'; export class BaseVisType { @@ -60,15 +59,6 @@ export class BaseVisType { showIndexSelection: true, hierarchicalData: false, // we should get rid of this i guess ? }, - events: { - filterBucket: { - defaultAction: createFiltersFromEvent, - }, - brush: { - defaultAction: onBrushEvent, - disabled: true, - }, - }, stage: 'production', feedbackMessage: '', hidden: false, diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index 3f88c540be1641..17a8b14b57d020 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -63,7 +63,7 @@ const unknownSchema: Schema = { const getTypeFromRegistry = (type: string): AggType => { // We need to inline require here, since we're having a cyclic dependency // from somewhere inside agg_types back to AggConfig. - const aggTypes = require('../agg_types').aggTypes; + const aggTypes = require('./agg_types').aggTypes; const registeredType = aggTypes.metrics.find((agg: AggType) => agg.name === type) || aggTypes.buckets.find((agg: AggType) => agg.name === type); diff --git a/src/legacy/ui/public/agg_types/agg_types.ts b/src/legacy/ui/public/agg_types/agg_types.ts new file mode 100644 index 00000000000000..1b05f5926ebfc9 --- /dev/null +++ b/src/legacy/ui/public/agg_types/agg_types.ts @@ -0,0 +1,92 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { countMetricAgg } from './metrics/count'; +import { avgMetricAgg } from './metrics/avg'; +import { sumMetricAgg } from './metrics/sum'; +import { medianMetricAgg } from './metrics/median'; +import { minMetricAgg } from './metrics/min'; +import { maxMetricAgg } from './metrics/max'; +import { topHitMetricAgg } from './metrics/top_hit'; +import { stdDeviationMetricAgg } from './metrics/std_deviation'; +import { cardinalityMetricAgg } from './metrics/cardinality'; +import { percentilesMetricAgg } from './metrics/percentiles'; +import { geoBoundsMetricAgg } from './metrics/geo_bounds'; +import { geoCentroidMetricAgg } from './metrics/geo_centroid'; +import { percentileRanksMetricAgg } from './metrics/percentile_ranks'; +import { derivativeMetricAgg } from './metrics/derivative'; +import { cumulativeSumMetricAgg } from './metrics/cumulative_sum'; +import { movingAvgMetricAgg } from './metrics/moving_avg'; +import { serialDiffMetricAgg } from './metrics/serial_diff'; +import { dateHistogramBucketAgg } from './buckets/date_histogram'; +import { histogramBucketAgg } from './buckets/histogram'; +import { rangeBucketAgg } from './buckets/range'; +import { dateRangeBucketAgg } from './buckets/date_range'; +import { ipRangeBucketAgg } from './buckets/ip_range'; +import { termsBucketAgg } from './buckets/terms'; +import { filterBucketAgg } from './buckets/filter'; +import { filtersBucketAgg } from './buckets/filters'; +import { significantTermsBucketAgg } from './buckets/significant_terms'; +import { geoHashBucketAgg } from './buckets/geo_hash'; +import { geoTileBucketAgg } from './buckets/geo_tile'; +import { bucketSumMetricAgg } from './metrics/bucket_sum'; +import { bucketAvgMetricAgg } from './metrics/bucket_avg'; +import { bucketMinMetricAgg } from './metrics/bucket_min'; +import { bucketMaxMetricAgg } from './metrics/bucket_max'; + +export { AggType } from './agg_type'; + +export const aggTypes = { + metrics: [ + countMetricAgg, + avgMetricAgg, + sumMetricAgg, + medianMetricAgg, + minMetricAgg, + maxMetricAgg, + stdDeviationMetricAgg, + cardinalityMetricAgg, + percentilesMetricAgg, + percentileRanksMetricAgg, + topHitMetricAgg, + derivativeMetricAgg, + cumulativeSumMetricAgg, + movingAvgMetricAgg, + serialDiffMetricAgg, + bucketAvgMetricAgg, + bucketSumMetricAgg, + bucketMinMetricAgg, + bucketMaxMetricAgg, + geoBoundsMetricAgg, + geoCentroidMetricAgg, + ], + buckets: [ + dateHistogramBucketAgg, + histogramBucketAgg, + rangeBucketAgg, + dateRangeBucketAgg, + ipRangeBucketAgg, + termsBucketAgg, + filterBucketAgg, + filtersBucketAgg, + significantTermsBucketAgg, + geoHashBucketAgg, + geoTileBucketAgg, + ], +}; diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index ca7c2f82023c94..cf2733b9a9f36a 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -17,80 +17,7 @@ * under the License. */ -import { countMetricAgg } from './metrics/count'; -import { avgMetricAgg } from './metrics/avg'; -import { sumMetricAgg } from './metrics/sum'; -import { medianMetricAgg } from './metrics/median'; -import { minMetricAgg } from './metrics/min'; -import { maxMetricAgg } from './metrics/max'; -import { topHitMetricAgg } from './metrics/top_hit'; -import { stdDeviationMetricAgg } from './metrics/std_deviation'; -import { cardinalityMetricAgg } from './metrics/cardinality'; -import { percentilesMetricAgg } from './metrics/percentiles'; -import { geoBoundsMetricAgg } from './metrics/geo_bounds'; -import { geoCentroidMetricAgg } from './metrics/geo_centroid'; -import { percentileRanksMetricAgg } from './metrics/percentile_ranks'; -import { derivativeMetricAgg } from './metrics/derivative'; -import { cumulativeSumMetricAgg } from './metrics/cumulative_sum'; -import { movingAvgMetricAgg } from './metrics/moving_avg'; -import { serialDiffMetricAgg } from './metrics/serial_diff'; -import { dateHistogramBucketAgg, setBounds } from './buckets/date_histogram'; -import { histogramBucketAgg } from './buckets/histogram'; -import { rangeBucketAgg } from './buckets/range'; -import { dateRangeBucketAgg } from './buckets/date_range'; -import { ipRangeBucketAgg } from './buckets/ip_range'; -import { termsBucketAgg, termsAggFilter } from './buckets/terms'; -import { filterBucketAgg } from './buckets/filter'; -import { filtersBucketAgg } from './buckets/filters'; -import { significantTermsBucketAgg } from './buckets/significant_terms'; -import { geoHashBucketAgg } from './buckets/geo_hash'; -import { geoTileBucketAgg } from './buckets/geo_tile'; -import { bucketSumMetricAgg } from './metrics/bucket_sum'; -import { bucketAvgMetricAgg } from './metrics/bucket_avg'; -import { bucketMinMetricAgg } from './metrics/bucket_min'; -import { bucketMaxMetricAgg } from './metrics/bucket_max'; - -export { AggType } from './agg_type'; - -export const aggTypes = { - metrics: [ - countMetricAgg, - avgMetricAgg, - sumMetricAgg, - medianMetricAgg, - minMetricAgg, - maxMetricAgg, - stdDeviationMetricAgg, - cardinalityMetricAgg, - percentilesMetricAgg, - percentileRanksMetricAgg, - topHitMetricAgg, - derivativeMetricAgg, - cumulativeSumMetricAgg, - movingAvgMetricAgg, - serialDiffMetricAgg, - bucketAvgMetricAgg, - bucketSumMetricAgg, - bucketMinMetricAgg, - bucketMaxMetricAgg, - geoBoundsMetricAgg, - geoCentroidMetricAgg, - ], - buckets: [ - dateHistogramBucketAgg, - histogramBucketAgg, - rangeBucketAgg, - dateRangeBucketAgg, - ipRangeBucketAgg, - termsBucketAgg, - filterBucketAgg, - filtersBucketAgg, - significantTermsBucketAgg, - geoHashBucketAgg, - geoTileBucketAgg, - ], -}; - +export { aggTypes } from './agg_types'; export { AggParam } from './agg_params'; export { AggConfig } from './agg_config'; export { AggConfigs } from './agg_configs'; @@ -99,5 +26,6 @@ export { FieldParamType } from './param_types'; export { BUCKET_TYPES } from './buckets/bucket_agg_types'; export { METRIC_TYPES } from './metrics/metric_agg_types'; export { ISchemas, Schema, Schemas } from './schemas'; - -export { setBounds, termsAggFilter }; +export { AggType } from './agg_type'; +export { setBounds } from './buckets/date_histogram'; +export { termsAggFilter } from './buckets/terms'; diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/ui/public/agg_types/param_types/field.ts index 4ce5bb29f8ff60..d01e059c6c616b 100644 --- a/src/legacy/ui/public/agg_types/param_types/field.ts +++ b/src/legacy/ui/public/agg_types/param_types/field.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { AggConfig } from '../agg_config'; import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; -import { toastNotifications } from '../../notify'; +import { npStart } from '../../new_platform'; import { propFilter } from '../filter'; import { Field, IFieldList } from '../../../../../plugins/data/public'; import { isNestedField } from '../../../../../plugins/data/public'; @@ -89,7 +89,7 @@ export class FieldParamType extends BaseParamType { (f: any) => f.name === fieldName ); if (!validField) { - toastNotifications.addDanger( + npStart.core.notifications.toasts.addDanger( i18n.translate( 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', { diff --git a/src/legacy/ui/public/agg_types/utils.ts b/src/legacy/ui/public/agg_types/utils.ts index fd405d49625eda..e382f821b31a90 100644 --- a/src/legacy/ui/public/agg_types/utils.ts +++ b/src/legacy/ui/public/agg_types/utils.ts @@ -17,7 +17,7 @@ * under the License. */ -import { isValidEsInterval } from '../../../core_plugins/data/public'; +import { isValidEsInterval } from '../../../core_plugins/data/common/parse_es_interval/is_valid_es_interval'; import { leastCommonInterval } from '../vis/lib/least_common_interval'; /** diff --git a/src/legacy/ui/public/vis/lib/least_common_interval.ts b/src/legacy/ui/public/vis/lib/least_common_interval.ts index 244bc1d0111e3b..72426855f70af5 100644 --- a/src/legacy/ui/public/vis/lib/least_common_interval.ts +++ b/src/legacy/ui/public/vis/lib/least_common_interval.ts @@ -19,7 +19,7 @@ import dateMath from '@elastic/datemath'; import { leastCommonMultiple } from './least_common_multiple'; -import { parseEsInterval } from '../../../../core_plugins/data/public'; +import { parseEsInterval } from '../../../../core_plugins/data/common/parse_es_interval/parse_es_interval'; /** * Finds the lowest common interval between two given ES date histogram intervals diff --git a/src/plugins/embeddable/public/bootstrap.ts b/src/plugins/embeddable/public/bootstrap.ts index 801329a4a79af9..1e0e7dfdb09331 100644 --- a/src/plugins/embeddable/public/bootstrap.ts +++ b/src/plugins/embeddable/public/bootstrap.ts @@ -23,6 +23,8 @@ import { APPLY_FILTER_TRIGGER, createFilterAction, PANEL_BADGE_TRIGGER, + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, } from './lib'; /** @@ -50,11 +52,25 @@ export const bootstrap = (uiActions: IUiActionsSetup) => { description: 'Actions appear in title bar when an embeddable loads in a panel', actionIds: [], }; + const selectRangeTrigger = { + id: SELECT_RANGE_TRIGGER, + title: 'Select range', + description: 'Applies a range filter', + actionIds: [], + }; + const valueClickTrigger = { + id: VALUE_CLICK_TRIGGER, + title: 'Value clicked', + description: 'Value was clicked', + actionIds: [], + }; const actionApplyFilter = createFilterAction(); uiActions.registerTrigger(triggerContext); uiActions.registerTrigger(triggerFilter); uiActions.registerAction(actionApplyFilter); uiActions.registerTrigger(triggerBadge); + uiActions.registerTrigger(selectRangeTrigger); + uiActions.registerTrigger(valueClickTrigger); // uiActions.attachAction(triggerFilter.id, actionApplyFilter.id); }; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 583b21ddfa4338..ec71a1e724c7d8 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -25,6 +25,8 @@ export { APPLY_FILTER_ACTION, APPLY_FILTER_TRIGGER, PANEL_BADGE_TRIGGER, + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, Adapters, AddPanelAction, CONTEXT_MENU_TRIGGER, diff --git a/src/plugins/embeddable/public/lib/triggers/index.ts b/src/plugins/embeddable/public/lib/triggers/index.ts index ffa7f6d0c0f448..72565b3f527adc 100644 --- a/src/plugins/embeddable/public/lib/triggers/index.ts +++ b/src/plugins/embeddable/public/lib/triggers/index.ts @@ -19,4 +19,6 @@ export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; +export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; +export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; diff --git a/src/plugins/expressions/common/expression_types/kibana_datatable.ts b/src/plugins/expressions/common/expression_types/kibana_datatable.ts index c360a2be8c7f7b..38227d2ed6207b 100644 --- a/src/plugins/expressions/common/expression_types/kibana_datatable.ts +++ b/src/plugins/expressions/common/expression_types/kibana_datatable.ts @@ -23,9 +23,16 @@ import { Datatable, PointSeries } from '.'; const name = 'kibana_datatable'; +export interface KibanaDatatableColumnMeta { + type: string; + indexPatternId?: string; + aggConfigParams?: Record; +} + export interface KibanaDatatableColumn { id: string; name: string; + meta?: KibanaDatatableColumnMeta; formatHint?: SerializedFieldFormat; } diff --git a/test/interpreter_functional/screenshots/baseline/combined_test.png b/test/interpreter_functional/screenshots/baseline/combined_test.png index 87f3173d5602472d092da015c8e58f354f0f9bb3..56c055b8b1cff85d7dd891750efdcf6aa198e937 100644 GIT binary patch literal 16994 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 literal 22801 zcmeFZbySsW+b^oiMnVKcT0ulWT0&A9>6()k=~B8=MOr{g8dQ4HBGMq;AT81*-O{zM z$M^llIp_P%K70Rj#@K&+jJ4KaOlfEUfTFx44i+iaxpU`mo=S-+pF4Lk z{M@qI9A{@I$Ite*mz;#s zmU&G+c&{J5Y(F@=Oa1SUEj(7RLIxqp>bM#47RmRDte zs#)j7*tbL~rQp)hbWT_r%q=;P3%I_kA#kEjs=29i zKd{`vLM6qO(|j<~SMN4q>esLKm+>fqiB1l8XUE;zZTR+QLYI#>X5`Uc#YyWW>)$b3 zbNZ%(IrKP`xsvLpS1&D2H_E&?btGd{%b!{3F*r^vCD=TUT3}b|&((@29mrNHlHkOy z|E`rF&s$%6(`!bCIkPdt}ZV_=K_)i|M(i^eC1%T~xmTHR9m zd~t`;^D2H=rM{$CLr_EGiS%fIb7gIpjvEQ5>py0TB(v!$lA$(#7TA7!etoY*b7fm` zHEuM=aqU+-pGtZ}jC0)RHoWURet=rxZm#MKNpx#@84!>` z!lh4MG~baSSt9?)Ts`^to8uUF%h@-F5y$b^EkSt`tTMBqwW^h0Rnc^mR%cyuH|yOAt&tNGFt*X2J?9pXnSN;$6X|oEl-8xO+D9i^^+bm#+`m zDHpS`!{C+CGCw`hD~jt=el6E0JkDrnB;>x&*@i{mBv9Zm{CRtK)k+=~pkQQmwzyu> zb9$iKYSOl>g%S4R4;4?s|Fu4nr;_sWxDn$?O`Vg|X)^AtcFfe&;d?9o{>}kW*@ItT zTd;b&n?0wBJ-wgGbl<6Ys9P8Zl{{HRPv9R=MrK6}P|&4wguJ^#yIPKM_xOoBj~xTR z^6ZC>j%?X@!5||>bVTw8Cf&x?h-;OcdW5fEi?_%Sv*_rLzIA$k7WN^j_9M51?Sl2g zgS)W)rx*PCK6zNU?yQJdwsusueO)Y4|EAA*U^cvkO5l(Eu0rJ7CK)p?v~?^|iRvxK^gO)d}T>LNQk^N%zwDqM;X+L}(?(zgoH?!uNWU0uct z8-)+G3gg}sSe*$!GoOg+duq~hUH73@YYg|q{TeubKPtMP^!E0ajlt&|gCl*VBpnHy z(K}>Z!0Qj{pNOTtdO3V3aB>+teNH}X)(s1$lc()~>*HtRHA6r%S9-!b} zFVVAYJ{oh~rQzJ+Pl`L*q^_Q*_I@*KpU%1v9A;?zjJ5&Z#{i|icv?9YE( zg=3?lI3CXxgrjR!r(!4ctYL4&N%4I`7vbe9ws6?T+4NkklI`8uMZ!pcLgbvU*Hn}y z%Eb#_k8bzjZf|Rwt{0S?FSF){|d_LiKsE!(&Z74Bkp%;&5>;v~dsvi47L*aVdH0 zT6zc;2UDn^+*;1mp@&RZ9^hKBo#xVO*LYH7%b$Mu{z{l;<36CS!D_kHM*l#z8VQ># z|F}K?n0wKtmL<1Zp5fN-eWwj{hJ500ZxTDxfph{t+-BrNbcgs$Q63_l)qRC$zU%R0 zx53r`-5HG%PnvORSWxj~PkGC$xLC6jy}cY8{cpr&Om_`cu%+)Sgnn%r}qgskj-yd zb|DIZkoLJcos{Nk@qr^orO#qE9a8dw?X43xA3JqDg>`)~@+}eCTFV&%-%r*Mdy z(iXw0CwVT}PVcUux*s{I#@wrJ(-Vn>tdTjrPhdKJXQ!wSxE!29xSisFjo1xKA z;;_Fsp%`q2-o@HE=h$4pB4&O|a_w5i zPiWR_7@h3PRj!Wr%VkO2Jywr3p!&Hif7KoP1U;4I59a&uP)Gi3$ZaMBh*XDe!EFVx z=z!1W0}OzT%mQ3q#7;CgAbBd;NJf9d4{+QdZUbxIn|ACVNwu0dB z+gOhIFUDg->c!5j#Qm-Xyq8v+DJpE5IXaUKpP#91Zg0=5-}bHTQxNE)*;!_HUND7@ z{|W_rH}~lmC);v+l!f&WEV*-@xE*$VlP=?w)=3+cZ5!7=PR7e3^x2cu+!bcHk2 zenAJgxH$@k9taBKnl%skpT)7@W>TTRnlqi_5-7rNX9W=&RGwl0Avw}A-IMU%rejNw zJN9koNJlwMpHL-P^pMvVY^uTHHmG#Q^?rRylP-JmYK{?YFwonr_G2;1@#5uMwV2R( zraGNqQbCdU!ETi-{Y$6P=1VTOJPt{Mq94{%tar!M1G}6G;lr|H1Q668-EVCPE`He; z{_Uk^IF+(;_qJFOaRCO-9^ecu;LM0BT+;5UkUvU?x2B_EljhoWoT=ouKEABxvt;(3 zX%y(ypJjf~A|9A-(s|WmV!rfXubeS>dV0p--cE5*o9wJ%XsByaIKL;uiF>s0xIO>>E$fS80yxp$SE?kE z$H%Ojw^(ZGF#G!xKY<&r-R4RaB4`dxRc^#OP6R!2xUFZV}0xc23Qu7v-$XA>pJr}6H zGtznys~2GLskC$xX45LObUC@tMFoF|0?zf z1L0DO@d^469_vE1DGQ|uWPl_aGp-w;!7&b!=^_UltmXWj)Y_Dtf+bKKz@|@Ifh*fU zS#vro>b6CO)L|T7>ZU5yOBR?i4C2FjQB%9LJ`tPca@bvYoI@&L%UWISn6tIHsWeu3SdBeYG$TBMoAP3L4BuBp?ROqZI9wR=2x-# z4>;GOoQBpyZ@m90tedkfG+K6waajGuIhZ@~_Xx_aYH}80Y}1YwhDzwrt7A^@wT4rj z()Hj_J=yB|tRPsA0k!z(WiP_-jqgy~#!K@?ydxrFh@1z7Hvi60FLO;ott zdh;eaiiOyl4x?I)m(8qQ>Q4e3Se?`Kx$X-tvNf!Yy^Oi*-TDL7Cw@1&UrbbA$ZmQ^ zDho<*?Ew^fcd;{8Ht?spWM~-%10P>|6b`>AW&A#o{DFl(2nEEeE=SZ)zYybIcAMAX zMNkE$S0z50f|pzdP|#9*;>Ga?M7{=E>hLO-+tc5(O5mF}T%2btz{q4o7mln#337t} z$)a5Ii~>0m$L|5$h}eu$HdTGx+VvWfn32-?_B$Fgi40I zfjIO!F^S0UDhh%<7qcB#M!hxooYosL@)RSmY2FoY{<&b*zk#1qZawu+N!)c}W_Hi% z3Uwun>b=#G;yN-Avp!n2b^oyqE;;9c0MvpZ61~uKLd5&kN_1WDLMvWP)0r<(kCF6D zRz-@8L1USnJeG2yzIY)66BC63Fk5|b``8C7j(lgcp+b2PACg|fU9aEgCS<%N4_^R{ z`20g(tcbKU19W<4hV&PYW}1WV(9BSG#CESf2THF#0C;%Y7e_%%GTOL3J-?uCs??k8 z060i$n#pr<+2M*-oW?*O0w`nX{V~v6-iL=vtE)daGhF_*`uBErmIU5rG`*v&E4X{Y z)^1s%QfhtIl5@R#pBS1yqc0wXe{wR_cmtei%N15ij7|ieamSSL2lrj_WUozHw8QG? z`HC@MKAr_M)XLuxGQnHZ8#3J(6qc+hIFX<`?b(*uJ+N`meb{i->E)fJD*(hOUrkkxCPq7mvT5caT~?T9sm zes9od*DV;VciXwGdx%&_SJ%=63es?3$w7T{g`+dm)r+=L9O{`#*ZIR>Zc_b}^?M-5 zot9H|wCY6oN(uKvIiHB#s{w1GRWyWeZL%9E%%@Ma{h7~#L6eFVV^B!BT>7Ne%{*HI zP+UO$@ZsAxw+QUGZRn=iEV{=pXhUzHa3XBN%ofc{0fYuFEcC{NxeDTB2m1PjX@UBD zKJf2rK9#q&zTtI?oKPy3JuOQ&AJ<`-U#c}cY%~M})c)xaRpDpLM9uxfUz-wH^L+&v zQ|H@dw5$bJ(G>q$w0Q|fkV&Xwi-9Nn(ZG6a2*#215?+6%)1n|O{Q5Yye(IxY>(wRx zKX)9K`lqY0=Gd^kwHkr?fh;1;E_Yab1tt!h>qdmwV&UTIpTw~g48I_xzxis+a^BGq zY%+Cxa&lQ=x6(Dy9IYDsBG5T~6KC(aFIV{z4G#~$BjLN2z0{uj7QM69a1EGo0o>M=GJK$dNmW-64m(^VAKslb z13Q?fQy~E~lwRpGPh${KntI{qNG2`cUZu1arvLH_&Srt+6j1Z?zk|L|8dh4W`}kCb z+@zcLv0GOw++%`Wy5hY%uK+~FA|J>XPK(nkRo;$bM5S6!iHwHadZ;a{tjvyncbn_| zIWMoRKH!vJ%o{UCUFH+_k0yNdZjZM8X3>6w!pCoP0WK&ewiSVp+*_oiZ@!29O!;f) zeV)=I{OXIdqy+pVq=B+A2Nbu;{HH5fS|wb@Oox9s5WYdwne6!{CZ>Xo=Fy{z+0$Mp z!K2~t0dK)dwWERFBpvx6Vx|kfmn& z=O)i-7hLb(!!Wnq>5}fkK}{WKSK-fx-wkA6PaF&^)BXa%OP|C7rblt*=@O@avlU?6 zhC=rD_wP`LCxa&;RUN}-$BZ7xIXHKz)3~T-y*R0|w~QP8hm7@I(iq>Say;<{!ZNi% z;c65K8G~h@J^*G*2No_?1E!RqCY($@N%juXcR|`Vl!M=^j{0hWr{#BUvYN)gSSrs3O#Wa`iWXhl2PRRlJFp-r1p8=H^=4tA zq>EP*Ig|!^XQ?L^$XEx^jl1CLfm_hQ3#$9=TNN?!s0IRXTN`zT@^zanOK5(lWf(n2 zn$&IIV6XPBF1=Qhc4wFehPEpmtc7VM9Sl;1i*4 zD&%Na-Ez_aVOufQrCVk_MU9SPAZqnOJlpr540zxdk8YgoQn=T6T$yRY&1f~iDMjV( zZ!scAHE>9GS$uQ4@qMM;lKoB4!}S>G-jmQ70qKiqfJ7~URU_&f+=yukrfM`UnqnHi z-5<$`u0*Cu7kF84IeH@o8Ihh;=4fb%j-JF;|U2YxDUhG`)I8F%y%Z8ib zMy1Pp6FLZ{#5f5u;V^zqk=eFFT&O=WCHtO7xV9qz1I}390oP!%h`z23U<0p^Um@R30!MZsr>=F z7adr<=u4Nbd^!7m_c9Kp4;-ufhtIyet3L7FXr>w}i>l<9^T;9PvOgy%C@3}lREnoj z&4T+mYA=ssb8}NzEcFifK2k}D<<;@?DS}KG5F2u_y-LnxLPA2o^rZcwM-*?k?k&~5 z8q#fK#UAbX`c!mu6Ko~&Gg@3m#Kj+p$gl%>odj8mQv+!R$0bH`r_tK*?hlA)-Ku}D zXJEstQt;UoBWmzK?zk+^93($SWhsXt&NzP98~r=f)Md*zR+LDR4e>?w)nS#P^}tc^p!|mP{v_A*LZiYU- zQzFPDxlRWmYyz%TUDYR7kWxQeg^J)1I`%iw{AvWiIqRFS@}i+~!pli-0Ay7wG!#m` z@nZ$Hc7W^Y;SB4cBaTz?&}aEYV1|M|Xz}6$_o@R=Xgc=R%V8+#vb%JA@ih@)p69cn zcSv};8MK%p-e_!R!VW&NbZjrAyx>T@p3QaHCN@9;eI?~TWTmFQ)C#P4HV(A^IC#$8 zHTyT6kZc5D(IYyLoDu2f>9vNlNP&r+j~Iy~UO%704{MgVCS}BNHa0h3QQ#jeJ-;p& z?^A(G&M&f;l)r5?HKi9>k?~MNL*w4PBx-v4*wI^x4ODFFkjBmW02H=G(#w4k@g(Ql zy$;vrY`&Xt@W`z9eRvpt%%=LxWn_!jc&#_Cj=5EL)%f`NDXk@aF*Gs?d+!_wHma@G z6MU~zc~^Ug|J9rI7an~FS5pUFxDYw?{HhiA!%L=T zybMl!gVhI$Wv*Z&2JsyT{=&4w5)=9+fzF_5Wa_AtaaeRrx zxa+P^W3ue?;|BVNzzPm`7KO*ki*3|Ee|a3)oBaBNw;2hB8KA{8tgBa_bW}KRQkP|+ z+HdinY1@7NEWKs2NJ5gpV-xPOEu;q|v(y6c$9}o@JO>E#g^>)tzH~4D4Ct)z&zAC& zC+Fa(3V4qygM-LY?DG0D&eF{Ma=RB&u889{?DVQtWxQEOH+Sqw&5-N#x)(8bgvC%E zn`Ipz!r+~A74Yt@dpuev$O&X7XiN#^2h%{91A@*_BO@a=%VR!3Cv2xGPQ6E9o;hdB zL^Joz7jpwez`aBZMkW~M2EBZJEp2UeIxjV=o`BMAv4Z5$4<#OW@y_pI?0=b?7HFol zv*oIQK!#SY>sZ*S5<3`oRu6W_FdK9j(K+`S8Lt=p`s(@`)b#raQhrUmY{*0>!O0S~ zy#2EVFX&cBx> zt7%-88}c_1pEqY|e3j_$4t^x@_xG2~dsfv35Vvo>dU=%7yx|T8o%^mt`svd&tUBc5kt;x(tD!@vmFTyw4P;sk~XtsFLcX?g9J#K8vRCj!v{)C00I{$itL z$IIBH!r-*7LH=#Lm0CFK2jLlAFVBflmGaZ>%jks1^gU zBtF#{8MpV!3VD-4!W)#R-=AjI7gFPaK}Sf4tB(q`OaxPnntJ>@z)LBu0FAex$HXMC zpV5KBdYQ`p!%LOJd=VKl_UV&(d5OB|mSevn-@TiJ9hen@M93Og4HCyf{n|9=jkz7z zZxSQTXDw4Hg*5qLLg(@YU-;Sg#2D4QmbW%EKwoJDm@Y7aU4w72R=zCHzd87}hmcwO zsuRC*4RffVax{}xi9us`bBF;dm~>#@aOwpFLgX17K9!2#@ZEn$_8N5bq8SM&Cc>8B z{VV%3c@Xz?%*c_=;6n84i@T_BggaKa1Sb&0eA5W{-4qZk=!-)er>8(+wYow4^A-iJ zNS0bYF5Gw>OpiSTltzLvAal4*0u$3_uJ&%1taf*}C%#NAcb29o)gR`Z+Oi>*X4TyK z6ms|7pfMFekX*)d4OY0-l@6|6sR87uNJj1yRYB+581#GNdFRsXx7}6E&8ZHjYp_!j z5RJSdf@=2X1dajcVsz8FuPKtAz=!Vg?z%S$%%s`b+2<%Qoz*K%aq$Lo-5Qe@9zx<#U6HDlI?_un>GJVDLk9}zuY*Tac<=5MA&b)rlI)ERZ26dw@O)$eGWi!w#}g0FuQ{I- zKa(XF3Iqp2PXewdhQo~%3@lQoO1_;7{7R`(=las+X9u3?Tm#{t0*ypAkv~bz&7sk< zWSff4Qy_roZf&i9{U`at?wyA{t+u z2CyJtQ-3ozAZ9YZ_TF7cLIWu9@!3}A4QhT=%`bym8QlRM^Ji(8B)-#^`v{04B9NDQ zB$s-Z8gHo^6%B(uc*PH|`KA*!B_q<1tgZz_hA{Y4xVyWX!Up7O33Pv3_k6x+(*786 z!$>)E6t**xQ;mbo!SYWo%hRr1l&uZ?QE;Q79Fz$(h@A4XQ|Vb>H~qFR5Y6X+Cqwgq z^@bBtoz*&wNLz;3{CjWr2ZRoyk-#4q*V9hY0ak2pAv>KiXj5;9KIz>Z^#?b*GzARZ z791rd+QK&YJ@Fo(HNYRP4+H|*d4giN>#{zd99pzmK?RDkMD1S{-2fFG^96WF`JOw4 zg8llhF!}tiGsXqB1DZKlcz6c;1+QUlV^k?q@$P*&a=9SlUj_qe7F-+V`FYN5LqqZ@ zzB^{1Siy2Rn2RR3N0&U;5nGh-RInYQC9q2Z-uZu2FSHIMW|7#`7e{7k-gtZO^MOn& z#ApsM_&WfNR3}p5A_Zz?S$eeAs~!~>Ck;B0e`?tx11bu+XJj5`tNmJdM7Qnl4vnsR z$#eaS_rUQLlMqwPQ3rQ|IK{c}GZMBy(HtlK{F$PT$~7mlyjLKFKdSWES;n9N0Lf)jepEmUk?j~nRjxmSjD~hT3G}EC)KK1uuw@`UnH(&E zZ9SgQTHRkGLShY!Hc;QV_e&xlk~{@fYHakZ>>GslEvlDhTQp=Gj6T;V@MvZW{y#4h0it&e_ly^cumaQARAxRK-sss#)6j z+0192v7_POSE30S(S-O;9Ve!D5i?vgk+=8;{-y+sjm%mxX_O~8O~k*Zlfb1yawl63 zoAlIa(3_F8+>t@_L3~gdU^83O0OdqneeVoha-Mg{Q3paUGHR#mW2+t&Y41CF(~JFl zHZ0zJGVn<~A8;s=cp(UdLkT`E|Dg^r#FD;aEyiuf7E+x ztn5Hy#z21*px1W{@F~RAf_W`8=$NeH_JaO?i;eogWSAd*w`#8Pwd`v3>cF6A=Ba>1s*Wbey~GX0E}o^@ z&K(t)!?=PrsLQqe6DQ(&$&h-?WuVF$z~LGqgPSlcYI(H;5FhVv=x&31+hZ-3vpQ8{bIhun*+p_{cJYLt!+94Kcy)mD#{0Z+{f?YSz|#L<(O}n3gkE!8ePwc zJD8F@KHjz&MYK)BQxzLYKnJl7UKpkVRj-eD58xC-)8>GtJp~g?mA{;BKsFytH=ex9 z1vN8mtOl(Z*Y83$*z((5k&C6vh+jg&bqm@f!g9dY8TC)jXMt(GM$D?vis5u>mZ8b~ z^QJVJXcB&VLL_FyFhnsb7n>V3Z~()P9w~0Z0ApyTOZE&w(Pzz*a8FT;ZmJeFAJD;= z0+{qf*+~2x5Ro39nCMLs&8%a*@k0s50*SJL)YGeA5Lwz~Wz8@47UKb3n??f7v_bEIGL$Mt{k&5S zOfCF%&p`hgd+y^S-x31tJ_d>FOAR1-`1*3f2X5~k9i3l|EqIlPx~{+-L+skMh0!d5 zaK1Q!gWJeLrF*f)Keei9rt;Emeuv!XHk0oCzgeZl=&J&-6-^4CWsBIxJV;EqT0F>3u%G zM%vQ?oHUsBBX&ZL4UG2u$TlGc?A%cBJU!r1N$;8jKWKE|b7NmjPmYF)VBFp{1RWa_ z{WEmWJ|S}v%4tXb@7~>EWqtMMD|UF-y&{`FG}xzW7_eN6DRV+*aRJNX(cNr&GveyS zFB;7un@rOgAvXK@Q4j+8V+}w|6G#kn?QRvo+(YT|!F-$ny2x1Wz;v7rfK#0ahT}X> z{E$gmX_!c5XMgkk`?=meb}8P7jwU%IbS}+?`=fSR6>Zg!_%XlQcB9f!D_%6A9>+i%;Ps$PFD22}DR-I3u?jqxk-hLsqI^gHP)a0EK z9Ex75>^T0xSE0X|kYTIw&yss;rF`YsNejJY0>~%~A}t+YR5pZCK*AEEm2nFRPW?5g zx=wHZg%9YHkir*13QAoPNx`?baX_rAF9E02plEoX57}?9iC*lxa+HC$7#7d#WUc^) zAfkF%ofU;#ch^F>Ghw+_pPBp227~+Dm%g)&_$XFv@MXX!e-tP$Y|8%7q^hGC90t_~ z3Kh|sQ&}QDScnq+YBqEU8Tdn{qd-uzVPC-K*j*X!MySRBFfJ(E`_P~}bSmdLLzEv(9?DZ2)?)jH(9zI&`h=sY@U!1;@zXZ@%uav zZnSDa7Ir^`>M1}DmU3Dk(e0mSDE^&>nP8V+HRs`B3Ve{(Ln*WSQpYB`p!T1$tJ& zlM&(rpKW6$fR)M(kZ-baJaKQp%yG7;d$2T=?d`7tvy#UaUG6y;2%Lcs2EsxAONQy6 zJ~d&TNpf3j!h$#fLK%~dkDdSnSR!y#tmJNsLlr|`oc-YG;l_U2IR#(Z5(WD#X0Hbu zd_d|0WG2IjE;PfV0zI3dCwjQum0AeV$`i{am?D{(AP=dZx+8>yfG$*>cNj4DT(Ur) zsUNp$gN|)sL4w5YXm{EA%RBgm`oOQq0|WvQ{S6G+*iaJA5DBDHbW8#lINCl`k!6F% zbk1v3fl&VZbs>$m%7f%^s(%gj&B8SG6fDX!WKIqvq!{ItE^7j?HG2tmG`p%|>%}%5 zl1*Uw0zn4xEFING6bt?!AW91(1OPB=U=24Eu6A0pJ9&W@^N-EZ2A@-}RN_63Yxi#4 zx#!RJ*7%OSh!UY#YFl7l-a~!iTkV>}mm1%+eK~%aEv5M6(#4B}gsDEaTqWZ^NzobI zWcB%KweHlF5D{TeRv`TPM4(%4jCZ-|R_C84ErOk~-l%f&uMph36 z8k!r;59z2D>O%#4IyCGY9t#|{Tqs{wI5E2I`zlCDN$Hc97mqk`w)l3sc~525xk>X` z+H>DIY54dg(VV7=3egO#tWWT8Ds-LxtYv+r@7r0OHez`2K+)m)b%%v-NhJ$O73-?j z*6*21!04~y-M!?n9G7R-XJS5|CxBtTa5(X)X51^3Jmkhy+mBBkWW^TopNSaNmM5rE z>9>F2qoQZY;b68Gm?l&8xjXF=o5EXQ8(@;h}s6R_nG z`Qv5>|Cybs-8P*cpneXNrEp^*hxnHkVi$&Y@JSNh_;E zRMI{x?j9{h^oYxRtUPU+v_HDjxNkkz&isml{OU)8W`%`{G{)k|Y;j)KKQYYcnTCry zOAbNhj%%sVgs0jJZu|0PI4Wj@tQMPX-!jUXNaeI(k91k^XGYuGGwoDYWmr~c6`2pb z>!H?#(cV<;m{%G+!nr6eZ z5UK5R{aGBm_WK2+Yy5Mw$;+ijl_hvZed`XeSCP~GX_5zF`Sv1 zS?jk8()J5K@F|3Blr=Pl;n}6Z*dh&HkHdGKhgnaAgKYsl95a!l=YDw!e0p;0X|ew#-NsU`|C51%s}d6Uv|`?X99VfbHEji-)| z#foDEDc$`{8~r!%7VFJ7khfUbzoyYspqBuT?4Fy{C;8``HizTdC=H|LBP#~vwNiE8 zbLWQMhKDP!juuPSq#$>s4rEnUiZG({dduGhODpK6eE;}_(<~wL^u%rXPy*-D zF-vA<=8u@@ro~CTSl1ORyljo4d#G<#XXia0xnKsZeturaj9cn0OIfSfVNudS4+jd^K*g{c=J^xnSxdjtQZ{N9=hVjgt39r$ z4tziFlnIEm1&ZmFU>rXRp59WjSCw;E997yIbBo5VS2UVfAIn!r_e^Kf`j+kMg_HJG zdhmkiIx4gN)6zGCdCRnn`~l2>#hl}OmRa9D07Oil4lmX@>%|q8Q@?ZP)Dn_C8GgL~ zR9|eo>RN0zCOyRYt}h(W#Cl2}h9{p2zkbcWI^y+2)Gt`|*|X}yohlt)J=3O~GG3eM zRAs*6=w^sVAKCwuf@;s!ofrWmH|~hbCZLmNC{}SpWq<>e%H3R(%VE-m(Ww};<*hGv zZ#3^r;8b%km!ucWdwqH}EiKJ_AU)gN!=wM}Q-kx-ebcn>D!^%&X32DlNC&eN@ z`BA!vj5w_*_oW9%z5gKvoU3^XeZV=WiQ<@P_6Oxd8YH7JjdtW<$VL|hMu?p#(BaaLhtci3>KaN+qwoKIc!psYTv-Vou zTC;O=X-i*R<$Nh!XRp1SD3pVR$=Ewix9OW;w=sDl(E>%u`=*#mhb}vphM;QX<`% z&Nd(660a2&#$Y~w7U7DQ8~6le;j2fmA=%R2KE#+GtOo6aLda7YB_|)xtnw?hgb1LL zo&l4d?tYwgd4f}M)20yf5cVv;lIvMdPqF>+{!>&57$c^$Gu;e=%xJ1px6hDR88Oh) z54;UnH~XDaw)FE;u;%>|Mbz9J5j%D~M%2Z{2fO~hHi@*1i~|_MW1B;6oU^BHe`M}w z$VJn?>>Ua8w{9gQLaC?-o~nAUlVd34#ibM|`Uxg-Jw4?#Z|Tp`2yd$1`ta@L zL{=o48^gOY=JbSy$_ot_c(^e^Ky+i0Mdj(!toyR=3LGY#sAk-k{p@8v7zUR7_j*57 zDcaf@4R3Ru|6bg5I_(9R)p)SkJcEUe-T&&e3Tbl@(5zO5w+YF~Q*l>E9t^Dx#zZ%p z{Ydl}cwFqwPuj%&1K7dr{Bm|=q~Too80q#F4^DYeK6K^xlJ)zS<9J{Cf(ncZ56@ZJ zIL?eFQpx!C%x&({@T#Lrf96z%FV4)Pz4m-n4t5dldym2wn+=+GcKN8xR~W6#fBlK& zb)U`DU+PDjW{Rdmx;NId$1E;6qzsKsvb89NTiVWxZ%f7U0d6v=9 zQSWN@r%1EZG{ACcPy?yW@>GxGEL;jf%-5$@?Ne97{KhOZf%3t_IC)#!+XJ~47+D`5 z@x#gbM^&7sFRL~O#a1W06oFO+24pdX-W8=n8UNNxOTE{Qm_4M2->(833d4u%eAUyq z1TMMP=g+(9b-;6V#haSt_C8C4xhV?^59a2RRr1HZf%g=IQ1E>kE}Ex58+}|XYsswb znbDmvV3OR8?xy6<(yQk=Nzg9QGI&OrA?&n^n(xQmGQBx&rC(=t1RUm~Cn9~g6BB3#A~Rp8-EBj7Rv z1%8w&u7{++JhKn~ET+BNiGQ^6DU8?dcaH2F5fS{pY@kI^Km-|p&Qq3ImfV+1!aUaX zOrtCrOVanKx?9EuHK*wP)75pM_AWa@Z>K`BQ7=wh|G|v>W*T_}OC3zU`B7Uw z1H#ECVX0L!PX8ZXGWff@*Z)HzqAXh3Y`?9g2e{e(67X#d>ZXIT9i`W6@ z)w=n)B@o2v6HG)Hqe}v>i)Q+*&Ug$vP}ghMg6;n_8*G^-#C-hu({&5M*No)O@GPVD zTNq|OM`&U918mC@Fm2u4Fp1@nW|JQr25%#K=B$^K?!FZp9)6Qkf1fq6vu&`YIeEZ0 zIDRf{*^v>TH;RZ@R}pxo(cBz6EWY{nhnGlkNLNm|;+*!KOXT%H#~~ zry{|`#QcIn%SG-69*_pTLI%VyTSQ5zP$JYtNADBv*x-zDETUYnu3tx?m`zIM6M30b z(2gOpFjJ3do5LQ0#|TgqyX$Ad>C1UR5kzJx>C3PVuIq`LuKTrjT_^MRmQI|S8DV7+ z!56LHHtV!Abk}Q8CMCIVwaRi}+~Z1QVqz|I-<{H(`>{7~=Bad3juBDl$UJdiU}hea zF_=({NEO>DUqzoJK-Z52rG|=XC&`275ZY5pOVwF|Jw)ZgZw@Sf({gxBNJL}-&zML{ zncidURm&Y{`@>1Pb3Cy#$`NX@p>yHS)DZz86>+xLJJM_!wxt8Q9guXK(>;2whwC(k zzrMZnbFZu#D3Ww4OOO|r98iWUiR$0KJhf-D)K3x%-edloH~%0CK$l=*==~K+lq0N! z#_(fyA0Ox-(Hz?FTq7C97p)p)9ZJgFtBW+2inp_sd^jQBh;A%W_LY8POQv z24StuBU;S6}kevKyzFO4~(QJ zWXLHSzLkNzm_1jgM3_cGFn3Q#s?V;QKd-k}ITi#G27C#IYHMNC!NCCpHF3P2$8T+I z$9|Q+%s?1fJ^tt9?X@E+v%d6P%*vpam2!<>l`70;1jq`GkAKnMTdM;3s0MALy}r3w z(u=fTAw`!o1M2&6;#B$Vmm{eyG_XMq?&3Z{2S0)?uOkG$o65)AW(AA|5o@ISR3pI9uMWoO>7E;BNw9Q2D2 z9Q<+D3k}?0M+O`!L(rZm6y#B$jc8S%t$Oe*8sJcDnGEFXsu9!F&8cc@=P+D%c)KtU ze@cYme)_lSi3$ZYInTcL(m+sHr?HArPfrg!JRgyg&}FSbbZhB-a&kVu`ToHBEFg{h z1_MA}fRLdE(;Z}rt%fwoxL=0-=exr!mHTdz9`$Ym^#9l*T68@e?g@Nny?9zPnwv~8 zWeXLLj`HCZ`C|u#Mns^Z1(JsjMl+6uca|C<1_cnulTJ0;uuPR_!^)yOcqSWwLm0Lcr&G(XedSTzzf2LJ? zxV93KOof}l&YH)LickU(L41M3-NiKBtp>)gIV2ZCB3(rzFev}YyO-Pze6wTl!|kGTU!qvKJ4A4sOT?IV2KrsXVXfzy2XMz#1sRD-)eib z))|1@%6)lf9ia?RT@Gw0ba*~DMJzMYVv z;1NBI*w5zTZ7G?hQc-1NmQzbgit3ry8;QX>$@~I@2A=QE2n@vfpDhlEz`V+1_koS< zyFx;`vDo$Lpr{$XdFn9fd{f>#o3lJg@bs`6YBcTTQL-2`&MYX9;xymSg4C2tz|W=4=3s6yvTLO}FkEC}6o?_B5B)q%jr#3aap~My5H_fM^`h#1iC|Xom~W=p3|yU1aX-Rdbni_m%@Ju52UH( zYZZexmF~f-5)~C0xs|6`yz*mL+3;B^D;ybIzZvD@tb@($dlbm??ozWr)$u&m(PW&MLPD zjg2U-8J|K1Mn)B*qWOnEpglxFgZbO`z_MZ=vhRp-0U?j2WGA8%PWEPMLFX{HU`p7-j-3@rCo>sSoG;1ZXR$b72&`8Sh# zCKQs(!$ac$Ssi7*7FBI`VQz=@6iG@CWg;S?trp;h;D-+6QKT*P7F*DP`?eEG+ysY8 zHmWnJ=!wP9OGV`wGDB&pQhC^lHuajPl%UoQmzJ&O*4Ohji_P0+ZFvz3n1O-e19&Og zi`j!q%85c}5n$;Wd2I@TYc%~(D=Dvsr3xt~UI+7hL=~=&pZuzDstF-~jDa4GG6XoCCI8E@Z805?1W`Ht|9fgG0KX3K*VTf4i;;HJpM>?a{q@Y9ub z@JLl0N(;qR5Zs&RFt*rRTL%}!>}Xeq^sKw2*t6ak=b(LTslPB$)?rC(x!vV@R9K-> zb#?XOl%MR0U0nsQ?H|ctl9P7{Q&V3?a9)ml69xNau-02>0ldDd-9sVR=?5$<6>F6I zis`XMzZux6MG|?xMKo^`&=p(v+(cA0bV2O;AH8XeU+wnxu&}U^mI9{i`GHS>;qdgd zG)$u^k8tJof0JY6^v})ED4I8$^}oXT(aXvO{&0Z#Ao2EBhhxc{g~E{X1McR_n9LLQ1PiPyYjl7;rXJd zLeB_LP&+fB%{#yMOC0t$lmvEWuZl}bwj%znhHgjSU@qV6>T24bKgDsZn*y}=9`%ai zjk7>mT3NBo&CbF|2rXXoGi(L~D7(Tgz zyVUjC!w6yHmkW2k&Q|=bF);DD(j3h*Z1O`s+73m3%?LxIx4fLPq+c|Q)W3_Hi`iMNY^QF46r5sZ@Crgh-PJE#`4c7yR^ji?@UJfIj-4@& zCE-uoe1IO;lahp1R{qQnH&|>pwD+sjCI}wsO&M`@R2z%oBYGgd{LVj{wUR>?I0G1Z8;s)5=#n~2G}G}dzxEgSROk&CBMG9 z#Dl=>D^-(h9~zRZxd+a!vFBzQ1QbDtj$ew5iTM~8hR^G8`0jV7ZYCIPs_N>gpws)d zy9MvEu&~4eR16e~Y8g@T=5(8M^?;d(QddpA;ya#!H20Z9iJ`^WRu#?YLM4)AQ2Xu) zhkG?T0IGe77mgTsc%+uux&HGxh8k7X*MB36qrYr6-z5-N^E_;8yE{v3NWO0Fe@t9N zV#Srdw_7q#o9V{vh|s=#UBgBvJX+?yWA} z0vzvrauJw7fWxUryF!1ZeGCE)U%LVWE>7m_lv~>}mku_+GBvF3T>A)AcB?(vbr-m8 zVnYA+?RCDuF(BZE)1MX9uZvEfK0ST?`t^VQ)O^i8H`jVSupI%M2YESt4zT10wnI-C z@ci8loXr8%8F|~ee<%Zo!l1^i6LEDt3To$hcxCVqjiY&i+cXf9IOZq2| zA20rYZD;XwV2V}-HmM$d4+XYbK5Z&uWn+7B9mzGlx96(M$IJh`zGC6&wJTOc96frJ zi<9%(`kev5q+C7^SQ^)P78Y&-)J#0fQEHLm3d|Ar zy@5_y!@Om)vts^L^S>w z{>i>FK@>Qdx26CzJqSDpWGb*ZT-OZ@D3H~?z`$AM4Vu$=kd?v#n$lok*l++mx52=W z(5MIzIl$x$VKlG;r&7Rx8`vZQ12N!W4jAYFXI{V{B4N}Za6pWP5hOv3rX#9nkstM3 W-FKg^bGCg43Sv)JKbLh*2~7aN3?W$n diff --git a/test/interpreter_functional/screenshots/baseline/final_screenshot_test.png b/test/interpreter_functional/screenshots/baseline/final_screenshot_test.png index d860bb73521ceaf40d4b03e271b068d5fb18fbb7..753ab2c2c6e9492950600b52b61a8241c79ddc53 100644 GIT binary patch literal 17033 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 literal 22852 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 Om~LLP0HLmWB>fNO{2NjL literal 32900 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 B)?oku diff --git a/test/interpreter_functional/screenshots/baseline/metric_invalid_data.png b/test/interpreter_functional/screenshots/baseline/metric_invalid_data.png index 795f2f7c832f335a1a1d78bfd9c820e1dca976a5..e0cffd065fc4ad31a2a7f09d7f58de66722a83c2 100644 GIT binary patch literal 1806 zcmeAS@N?(olHy`uVBq!ia0y~yVCiCDVASDY1B$H4iCDcuu~YQf??lv5P84^L>lmdNFQbpc^O2E3Xg`#Xo48c4WmT?s5Bfc9tTm~ aaE4jCpDjfCnrb^JYCK*2T-G@yGywpYYsB;b literal 1920 zcmeAS@N?(olHy`uVBq!ia0y~yV41|gz^KE)1{9egI&&`r1G~GYi(^OyVv%M>FVdQ&MBb@0DHC3!vFvP diff --git a/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png b/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png index 580889bb7deaf3f06eaa5dcf06737370555241f9..14457f0a4d0ab750bd49fb09b1c1e946b3611365 100644 GIT binary patch literal 23705 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�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%0D!`SK?hshr3L$*aagIV( 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 b&~h=8fy36? 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 diff --git a/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png b/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png index 916a284433874aa33d618c30dd8751b32819e457..c4fc4d3979152affbe4386deba159c20c9e5c5a6 100644 GIT binary patch literal 22004 zcmeFXbx@tbw=I|;0TKvq!4DoBLU4%S8X&maAp|G5hTv|&EkQz%;O_43?(P!&0Mq9u z_s*L)_r0m9nm?xMQeUMG=j$}xySJ>hb_acsm%w=X;_0JDk1(VpMU@^sLJEHL=rJ?u z6Yx!eh5FA&k5uZUMBjdNe!Sm;qCMf)+O@*w6&@LEre1SeTd|QRX_rOLJ%UG=L|(3qZlBC_=eC+Rba^P8Jf17RLjs%gxyB(hfG%$a?6kDwGN-D zR&#N1JPj`C-Dd83bmh~9+x&d>BxPl@)Hy_?<6nw}?W*MJHIYXkJ)wlSZ1u4niOkf?npc$H{^76}r$K`OnhLLn^ZOk_aBO~!#c*HgAtcceW<~Eoj z)K%1^+cDJ@fK!E^(<*Y9;rJ)%m1p^5rv()P>?qh~?9SIfN%C3zssP3@sO`xrZHi*9 zAu?2!L}4N?_5_cZm^hS7B<#`Qi|S){y=xxP6)-QD{8S7sIqm58Pv3qN`j zkI{X|mZn|bEY=_4RBa>+E89PLecCqf!ggl$_j8J3X_kmGT|;x*W6Td&9S7m2+sA}9 zlk#)o!FY_J>uGF_u%yNnpA)DPk62@oC6qn6rxWZTVWLMS>`z2Y3XG}7WJ9Y+sX-I}^u5vE8V&t}w3Wv7Wd6q@Rb)nIFxkLF zzM8F{(4x5Rr=?s0kvsd~`P0#UDfMLG;2by3a!iSE@-BP&> zjNqi~+P3uE#hUKlce6Mxx}cCuHA(2!+V61wnYG`XtuS9Fph$n`UhTr|DHZ}2I#*B6 zM+u33#>vIylC@&wesLYYUde4PLMgl`U$;EDUP&gfwmpAtR;VLG&GSdM%v<5oOMdS4 z+x6K0;)P^O37;dAR;5*!%H7Rh8Xhu%dm$DrhxOiAQM<88OM&U*x6BHT7%j?oS8GGe z8kMAK=eskh@BE%p)tGjWSbw?L=Mxlb5*D(pIuyD&y-7ZbOpcC@b~&%$apqlqEFI4( zW|b`Dgq_(b3!$d=ng5=a)ZjwMTWstexhD`v&GKr8j37*sYjkX^he^-t zj0J<-Qpzfc+Z1~!BI%7TJf=QP^9I(ln-4qq@?6>6$K64+9Mi8R3NN@1P8_F(TI%aFQtTrq6_w11&u|0Tbt4=vMYOv zS{@x2C$1Z!Nj$Kg%N9jKZgxc!&#Ff!;(oh8#qZ?t0y}EnkP@;A9UwQC@a*mGUM^83 zv(2IHi#zK{^H`7X@0Z=>`7C9nUTVRYzCR=3+0);j<(U~5xW#Yxmq-M5g`2h?qi|9B z3K9+bSmgOdumgBx(47ql&&P(z|g z&_zY(w?}^cIYDZI*+p$IEw++9Cll@so>GfmD%7bHzs$K=kq>xIVbZb3)MGtWsFQiC ze1|pk*Z7m3poWqXr%ymw3+}6uO7M@_U84PlQblydkXsn2G$V=23GfMPP4#n_EZErN(1q$-)}459peRHQka13Y#Toe{w(8j z3gO;Eg$qcU$#h_eb1mJ#>@s6?bc_bgvXBzx}ekyCc-d#bqpa1^6ErQp)yO?8o%`(um+Kx6#$JXuGI8!enG=CPk>eoH> zIfEihRsQ~%+I-4#ea;$lwSXscabw2Rb?x9l&Qrab7a-Tg+ zN?O|RsPV1<#58cOl=JbiJD0O_6W)A>xk29iPf?J1b|_IqMe*swLGWDL7224Tw0tM= zoYQ`WS&TR^bO<8OpIi-vM}^IO2=5-u4+)e|AFjjt zHOJQlZiH>@SD676o{?4x_K?2)nvg)<3IbDfa{eU0GdA1OJxY?D2C8ag_INhcIcc+M6J#_KEyA!LI)hz9(ZN)w^Q z#YI@6I0l75zyTsF4Gq>fKT?@^cv>JhQQ(k7z)mggJ#2=P{uM{Z@B%j8TcvB#T;{>f zWG99<=v;3}m@-nQ#z4X&YDDye=M;AQw%sbYg&0I+028_O9J1-(L;T)Oj1eOLmM}pP zcdU|RLz_-|w+pIkYYkDF#Kc7BQb)4%c4F^ya)^~Fvsehhig>L9hJnI7K}ytdADecq zePVt2&^$?f!bc*(9jbUeSZ)4z`%7LL~!)o{r&BsE?<5r*V;4oyWZr|n~fi1 z_p86a4$=T|Nk>hMSXS$_C;M>BZkLzUB%)rNrE(vl!bb3Ko-?*mH`n=v=FuGpMgRkaSt%yuxhPYj^@ZqSvw&-zrpyiGL!< zgTR;&PAViXzu;z#A*iu*{Fc|~va4j?u8(DXe7uM4_*3RhLM%8lwW448lkk0p);gGT z>|VFr%X zG~SlqNE^Gk+B|v6iE%_@g2S98EfMDxasNxj3|_WSa(|7w)eFk&9J4e1{_WvL43`5x zTV;;EzP^xdHA15}1ETsmJ3i>$X`k3>@0h`mVQ2GW59}e^zuUHUyNhn0mwOudj>(`b zcU#)-?(Xd7hx=xDFF&G|-S}fdsv1h|9}k|MpZ|R4cbZV*F!vl}){Zx#?P3%bFf1;D z!Q`O)Bp!2FD}J{NQm99{3-{nISOGx@a#`h!qv7OC*%td==0Lu!YQTkMu{v`?#Xu!) zk6YzIousrhB&Rj)d3H?&hl^$3r^(qJ zFO<5p(!mMs3sS}!d)O+AU$pr0@xByZOAii91<0(wy^~8g^ zI~}t_Acyc`lp%ED*zbI`f?_+tb?0W(8H7vUlY1cGXrLOhDQ7zYPY#n=jBEy-7i4wp z`C@0ksz0~YI&qkfevgl==lR?(+VA|!i^$~wRQCiG;CCR%0Psfz9ZYe+ab%N_fe_t85gL2!e%KZ(Oqu&@@uKd4TFD?S&U zf(u$1fY%ZER%|;F8frzlVyBb13$6y8ahOw)6m+sl-Wt{ojp%AFE-tpfWv({jL!5)n zxHk30+efbhw`$z4pYoZMs2_ja*&$9?SyM)(prFvMfK7CaTaV*#(aF0+VVEyb(eF;? zcI>KHM=57ZFTB-d(ysoOIZt_P4raOSUNZ6#bAiHf$Z3CEmf&!@j=BC($&M4M&P*_G zvb}7|vA5ns5m|2wUXY5|MyEV2xWu9jCZreH52`X!4Z`WL4d{5L+gbnsWF(1_va&{% zCoTxehu7r4wMe4okI#9Q3@2r{=+~b6J;iS=7|R)oR0etGr~9?tcQ(E7(~UmGMt8p6 zcs7aa(+vi_M$(PG_{{%&xw5wQUN>JeoAck+1;ik2@SzfCT~u8B2^52ZAIr(5R15Wt zkhLXLP1nt5N4e`njgym;-TZ3UySguC;ax(L4H~rmbe2Rmo&R}{2bIF#_Rx-Jrive4 zSx+K4rfHr`)_WQ#GPUaStKEx%-ixM!u3ZboZspJDnsN@P8dIj-~??>Du6$tMp49VwiuCA~IlpXO*|)P<>@ zD#vtU*wQy;h;f)7)P@Pp{uWMyE;Zg|WoJhzFD?QEduaStH0u$+`xQgY%GjM=7= zR&&T)mDUSioeRs$?d^8c-15#O6q%NcR#s8_ryGq30kVMfg_^CIjnp$xj&R}%b;_CJ1dLh&{13mrwd;Z- z&Zwxj@?qqBzA(qDZjS!ri;K>M&r^*QWfwD-YtQvOuQ9d;Q|WUwUs+49wEAHWIqYAd z!SnJVU0*Cy5E7E62Eb2h_3TzJF-1m0^VN!0gVPmKI}17^Ubinu$NlXJEiZp1*s~h1 z_w&6Z1N1wqPVmcECLkmJW2xN}`HTe`w~wLy=>k6UN;wyI)mi|3aqQLk1lUyZR~&UM z{3G2ikqP>)hXZ&Xqf8LuCr{?X`04Ya7hBr$+|l!u=N_#n2A#k-*h7y0t{OJm!`KBZ z-)!MX9?m}3gBemBz<2$n>h-o&n%qa3Kcr-(4Nu48QBliJq2qN46$S?a0FWdjV@Dxm zDaNQKINTo4_ONi9F9y)_Iv=w;?2Wgkex9tyRIoW-HUL@2uUhS_Yu2b!ehvjs6buXb z$FRcPDKAuLf$OD1`x%@lr<`80z5O&~W7jqsDEXY6zrTPmM}IOZv+D$j`=}`%r1upm zK%v&3u(7dS9L)F!N?NgFVKY(!-VmX|HjpA}Rl8SM>ii8DwPoS3HlI0dc}v+8>+;5U zNSIZpQC7af64w`i6J*8fy51Eu`BeTera?W)rQw$oSMbPoBS! zvYKtA4#%eMGMbE{?m9-==#5=D`T=n7{#+RboD{*`8Fh~<65tRc|M+;q$zKuC%DK6@ z2`Ysa#DXn}T&6WqIq#$n5;By8sBt4d+AO@ju~mpZ=oG zya*5*GC*vYuL0Suw3-XjV4)~e8eO8`!ikAy_+9ub%Z@roN(%3znz9o1<<-uXGAX~k zZ%UqS!^@4{xSy0vO4aOXlmO3}f~0`m@R@~ArTUnq{L>;Hwi>tPVqA)}taK~xyj=(z zRHx1nL&1dT33WP!tg|y45VnAt6AXv~=J{&Db$yd7B2|Vsf!mF$49Z3m(qU+@dZma|VF7nKPAu$`H-NLP z11ZO*Gp#zp#vkrgvFUn>R_$F~0pEIuiWpXFgJMh#JL~zzYKXJ4eyyUpyFWFUyunD8 zl9Hm$sTG+)wzjrj->kA(lm%K#tE-?O{H$q&#Ln04PP2q4~18_p657*b%w$%UrL{(Vh%IznY zTotM8=_v+>)>cn)8FQV#8G3pqa68;s^b>LZ7Ew9|fZTWvsE&pr^SwY_k&=;FdpJ8i zHC#%wOsFtEAyqA!Y3`5TG*bQi`K7S1@O)rV5oQ`CEv;Wu2)x#+#W(dVDpam+Yykc& zpaCpInaVHH(d2oBZOZIrf=zpOXFEyeG#{=ZCDnt+qUj6U+*12aQnMC5$HBzNn3y3J z61fC}1w#tWMhh^Y)0G8VP}_@nm&3+7{_8)#^%VP24~H?h40$?0A@aF7|Ma1WT$w(C zcCI5N9&ks$ffB8Ml1`(5N>Y(~p`$;VKEz|tev{rTj`?mt7+VxXQXx&L0#0d7F(A>A zdu9<+ST9M!6E(Ii;WG$?Jj12$0ug>qkwY)U>}jn4ttXsfV$Xyf#dvz zTL0lc=BR})IADAkMw8KriBj^G;R~(brHrbhKs9d0O%e7WPynuAOMNSH`^{-dYal$; zmUnODR|NPHUhqNbBL4w2mVYc4o#J)mkGO$u%&u^n_Pj{Cf6KQt>|2A*xQ zX}^;PxN)ROkIjlsA|kaJKEyA@b$91J;iPvIIdFa4&01pBO68?mD=w*!W6HNppc=5> zW-|hpD9}55?QgIgN;ml$&eVa|2|q(Ew*zP~h2yHmrq*#s((`(=*{NDfQ)c;SH$8q1(a%3=Lrs%HcA7Q5Xj3G&TJt&o+S`uckIwd0k{YAtE$mr$Xr zH)Qv{9WwFLb=D$$DnO5R_&g=rUI0{i{mv32`syek${S3A0X9`^O*j6@E&V&VW(#@9 z&~qL3Quib07MGn zlKD{9#%?qMBVhKfs>}B9N~Rz=3~5mF{BRFR@MHY^C~Gx0G&?J6Ri2SCH$gE| zoZBu#$Hu&0T1u)T6=;_nnc`ue16_8AiRTMu%RSM{_R~GX1w3jWp7p~+tO$sxl+kMN zgz68nwO5B>iGC-LR@UT~Je^R>W(CQ8>D{(lY7;7~7U)DpwM~HUNC44|>Tj+mulZe4 zRj&F8#rm%R@`4bJX9O%AIzSiZ*xSjejlzW!&@uvM&EPs3T3VyYF$IVB>k&`!U;1i% z*<^)?IP4OI2Ga9++%QAGGbpAs;f&^zU7HQo$8+R^7LCKyBRQLT&{KAp%QbxBPmvA|?!a8O;*io=KkVJX<04D)m3MuV6i+T;@ zWv=J$IM@oOJ!uUIirIEz_tHSh=GcSlq&kiFH;(`+BnPnHZsy-YmgTh#2Aqr)0Sgn} z=A;{S0?diWv>A|JX|W)0_0;({>xF_yS16Mj4x?&6rkdqUEg81c_FN7qEz%4rtF)eb6SUgVBZJ!+ z)?Og5lh&$YK55xrF!@JQzth*2nj>F1KF4Mv$$^9;-yxqM5XR=w>Z(8a#YbW_@2Kg4 z5E}c^fgbYEcTg4I9tt$lW-@r@WdXpfrNH{RdqBSHrQ7qeCm87T^m(eeqMm$SRF6SF z3!Xb7Hy}Cksh#*-P;d@};+S2bquDYBlWa}e z>*Kj&)rOt@H3{df+be<9F_yQi+9TOoY=FHxkU|cl6A}XR)6frmh#MP)*T-A0*$h>S z77=Ya;G%%5>yw)7w|8&)H3_hT1bl@jFw64Pih=_J^MRmk_ja#RhZo42gEz)g0soMi z;=8m&{54w0(tr-^>TeVW&?J~O;oNzzi=C;uErvH=V#ucd^z^h9q=P6CE`xc={ukU( z$e^p)Bm&@b9QmrCXJH%vqf1~d7?)n&4%RN!PsD$vVVBn`(z_Nq!Y13Pu`=|$qktpR zKUz8VrAl+b22+M42sr%o!-o`rGTHMz>bgKJjP(u-Oct6g=LTe^OXH-j>cj63RHtKE zXqmR+XK@D{=GVbhyw2OG(1COTL{r%$_7|qFtY^r};)QST#|VmfvhT z+ag}IF#~7BEpr7-7u5qHip1ES`?^=El=5hbm72eD*IgX$j^#buKYl+p*}d)~~qcdop9jc!Ms1#q-(i7hKHm(CY&g3V+j4$uVF zHPg?9I(=2ZmEqJ3$k=v}&AW3!0UO>yqF3ysQ6!143|>JGrimqhBF(YZT!rFNzO$A9 z*SPw3$8H%@PFkxO>nmY$c6so!4A5&Cf4Q}f2Iwe;a3#IQ+=T0R)UcVKe-Cd-A&~1H zrm@FB`h-`ro|}suDR^*GQw|50JrN<4|8z-zr58>n@V07L7&JInL)GF~epsbyRzv=G zBP3f+_Peh2=U%|DF^NI3@PAjr2tl!f@%jK zNiST-?2GbErE)exWWkA(3ox}umeYm>ILc3>MbdhY$XT3qb|0;ElB zQ4t%QT&jTbvIftE#LoyNifwF>G=i60nHsCE>_8dR-q_od0d*3qCl@ID#>c}WywuQh zR}h`_G9wvcjGpEk^67jsKr<@b#hpZqN|~;vN+MtpSPtboBj5tv1gJHG+voO9am-rbT%)6-pQcu%N}XL?6!XSYLAkKqkcJc{aqb|e zaNE4mgXc!xy_|G;4uerypx^-NUC>7H~Lb9+@3oH&eafObM1<1s>WXa<{R9d$s_?i2j@H; zf!Eakgp_vg>qPFc6gU9%s~$Uy5NTKL_cVJ78Jvc-yc86xDokYnIuB4zO?D7~N|n+q1M!|B{{msfI3Hn~?g!nXDjds?o5Pc1bz9k;n{tDz%IRF! z9M3ANmaw)DJsgclkW5I3wx@!Oy3VFj_%Vu>ZHTr>5OizABS@vKerxAKWOUPHJYAN( zXG6*P0LjE-)lR^iY?AP-IU5vk20g04>Q-`VYLN!A^Oq|5s-3B-jn_}XC5Si}&eLLe_qXKEqdgK7=+DQF9)oo5D zP)=*u<1RY?b3D~af37sGUiIwWZKnEONOZo1+2;IsNB>Od8$-A1wlcp0B}c6 zRk~OEKgI7|v+4+03I=T-;Oo~WXPrdf<|^Nb((r&5kYu>ZAI(G|TZ)y94Kdw7b^dgC zHYdze{nHOvD1b%~Hc{r(p#;VE*tR)_9Wc<8V$jS&bukz}dmre2U?Mti22QCn^o6u8 zDjW|ullVO&q~l@H;*7|R>53)sd84Z zgSQNd8ZVxt9fDOKFC#kG#2OI&Js67_|NgNNwo797ex}r<*iu6wku$qT#@}GLNbm5GFgbAcPDxSZXM;(37Orz93Pt-?vdbq+{@t}7rZ3VxZLo(UeX2g;Nzrny9 z7#OJh<$+ez19}(I(4hj9)XX%Bcc2FYFs6)d;&ZU(KG4AGT+c1z zwFgxhaO>~Ko(f~2C+eI>EfK-tvdjFOjQ<-kP}*thm&WYfGH@Z+2jIGrY>FT*94LYu z{&Q+`t{IJvaaBjX;LaNXaGi?G=LDb++y=r1|Bi=HK>YE! zKr5%`_$OlZ?cuI-hOe)lGn*?0xUaDlK;gAo1ka%a14&q;j0pfyQ9+{h{&AB9yGlk{ zdNUbu$?oqq8mnI8J6Bi!`}-=z(sj%6LI)90YchUF|8GXTYaavpP*_pZbzGZ7IQ)JR zXf~WQ{Xqg}_2o#&N%`kH7g3s{yS)GkKA=X5Jh&%;9IKpVV*tCe&it4wfCd^Dps@w+ zcnJN|g20G@f!#}KAiDqc15eTaUw;G(IQca8t)QT;+lxunKPqNxxW<#%O7$7Px`qY> z{WkbRDJY38bqE&=OjsvKC7C`%P1Laus|OO(-93V1g{(YGbH0?~miZwbm$Iemh<~(O zP~6;^A!(G3_E>99S*LpScc>(MiKep?8&C(61)Bn{2>l2>g}5kHrnwj@)@b$=t)zJ~OX_#h#Sy)`=FLT~N{j zTVUJ_7{65)D#b9<-w=)OKq5<%T)#&G1C0&_&%c))*S+7{#Nz*gI}@y89d6y&-jy?MWH6&5Pls|yj!{{<}lY?CDr*$p- z9sZIkeF|f1lH!w!tRN&Dz2?#Ln)Jkb&!^|$?;SXiG-v@Ot|`Mj$}xSBjv&=w^u4Mj&Yyp6~;CLt|J8=m!q zv2M`3oz&Hq+~N@yoiWT+^xgA+Rcr@lNUPxuI7wDGwH9Vp$CdHn{GU%p?7Xxzl3lmf zi!f7_jA|}A>@|Y)>Hl;ziu(myL`^r3W)Nz_OnR1~u*4z)#~denGXi^ASh(4R{Rsy!K$Pn zOKl-ZKB-Sje9RtSI6Bzb9PcO*z7g6oSR!#V!|0-h30g>NTdm#Ii-qH!IGs|MUXHRm zqcg%frzqwIiGoik0y1)N`K?K2q$jNuEZQmW85}3Sgz9;GwRpVHS!!&<^)uTCkpE+s}j zzoD6Vfv(&CoY6mXJLBxb4ZLL4B3LiCA+~N{~JRyVPhgHMoZE?^k%3i3$ z?HO+uO=-@?nsr7(kzr9X&d}xwe1XJm&s;Yr_oVm-G~On*U{xQ;b!rvGh}NWXF6tCFdbyIh zI=W2lRSXN|@Kf3(g9tL2O0x(p4YlfL7YX-~cG1I)U(|0l4TBAI_ix@JA+fD~m__}p zeznjYNm==jAYIvly@&SapzBCU9>@5g!_VGx?frL_xEEqq3)gpw%Ly8dk7_~i?0v85iiBah8%*@= z@Ps~@n>}GXI4p3ElUR?^QI+@ow?E8FW|?tp&vTKGB7TZ@m57E}h{v5!sTPE_l^lgq zCVS|jRxOeQdx(LkJ0cg2?^In~wY)mD9s^a#sW;%aItjOQ^R@NlXx#~P& z-Ej+1qt&J0h1ctEX-Sf|aucU--1v?31+>yuOF!{zVK8&JST36z5RtvGZIYavhqJsj~$+ zQaOy-fTckFk5Ta)6hZhE3j&j#ZXZ|3?3ac3C}XJ^T(t7dB^=(U=gKHk)P1AaxP12L zkchYH__9os>n{2vdkSy2IC*KXhN}rpNc;`bai!z35xThU;VKi4P~B z{;JFukNc1x`!!N*+UQ9Xt)m6%S`{t(`M^1n$|dzifX=IZ!6?cj&i3$Ji8u`^Rn^o} zYS)l3>5k`+q{1!fO66gBjTUB*y=5@RIgL$;x{0yWDM)JyUz^r9b6Q< zWMm>bRY#WO6N}_d7`JEeH%(k%^(`h;!uTg*f*s6(ivcCqOtL8A^ z(>qfuLmN@_pA~oBq6OY9NOFY|`|aY!L1ZMYSC(kZ>i9A~r@~q8O(Fg|^f>k%5!1Hk zSIRpmMEGiiS}9?MS#}F0poj!#LAQ+|D6b)X<%e(WOZ@dCA|AVc(nL~itdBD#sMxAy zqwa|=rN{X+&_rtkA^Y{bP=esLeub1jrTMo58nf9}gqc$%3PH(yTyH^_d$%D5I$eb! z^=hSTCt+YJ{$Qj&Q=il9?~Rc6FCVuU{T{JpR-{gjGI0;YH(#^a7ohGwRsL)9Zp%Y{ zI)usjmlSffov%MjE86yFV^>wg^x zIL1t@cbavazt0@JLv^!7HjsN68Qtkn_O76Se?#Ig0ZD9di^6Tj zClQ8}zD17y&ua<<=4-ki1n}HMi8NHhP^rdW_zDTfE!|be4R>=+uUg_ETF3-&eSU-5 zp*pjzowhd_h6>fxhOjk|gj8f;GUi;27Pk?-NRy&vg?wMiruf-Kat`QYH|HNWtY>b> zW32xV;-y$$g&CvwHuCh2^@U@qsbO^?oYI+p5=uK)`)t@nkw|0z%>T=_4MOH5 zZE;qr$ghPNa`kpQt(RrwXH+tujFd&?BZ?`}jC$8=b^T}7WLb$qz5q_JY5Bt;Alev3#K`i048lUg(plnkkQQ( z(Ln4%gJm^-GuXTAkb=1rQlDSok5-oW8|-Nb^q}0I$t)P_@V}FIs(bB1uiP2Ueb1!Q z&J$-_X~Ia2u`at6OKW1hK`?ynie8vv^p(nVi4T>}Z``xuE0s&T*P_(cEN3Yzndy=B zj|Ov*j%(wEyEiPBGSbdYZDsTQBRo7&>Ce{v(L#&nMQ;~93OoyZ4F&|vS4M69C)mp*R@rVN`rF zdu{&?qul8rhc~^Tj^cN=r4-tcm2+Iw6MD9+`x2bePWg@H-JQtKrqjVWBnEaYMS@zL zk%CDA0y|{Ozv#vff8OLHBc0N#6d$Yzjs_$VtDd!D(|xoy>6i-X4#pe3KGVs%Uahe{ z5jMmmzz$qT$Z@iRKEgTLhls=%+}_*a=bQS^kelmEQkd!A^>O&CSkFkTs?$?rXiMUH z9q{>2+!x1=qK>m#Q16Xm^D7PPmel%(QY;5_)pb>Cf@ewVK%E zSGVejRL?VU`#(>2WuSy~_p+^QClA>kH3@V?dQOt=8hMzeXk7ZDiPFVIUD;wZpu8Y5 zqcr6&VrHafs`@%OWn{BKiimEep^g$|W)Ca&H^|r9GcJx#evwiidDA7`{X!ttCqL(X zUaA38nw2kGm-EKV4th^!O1nx(nqLg~0*Cud+Ghr zM4#rwOgDvkUncSON#2oqc;L6GRvpq0pHjVF6p+;SFhOh6Ts)*Hu_k_hqw(c;#CfVM zbODzRD^Xp1wTt^N`KM**>WR?2kbmg^o$+_Kj3R|wi!YO%TH9YhniqBb|5oCv-@i$C zW7Z}-tEuIZUHaAQ&nhYJm)hilF#$fVM?p@GQRy<19$q!U6I^W;5!~!q5wD8xH;CHu zs`jaE3t|kom#hrt+xDil1;PsE5%`}UtS*Xp)4b2~wEwmnFOb{N^tAwnvwBqE6EQ2v z*_!RnUp3B2BYW0D)=U}HXWY=_@i?+;WKsnfXu8+;-qQ+dbNX(Vf{Ds}|Ksz*wCA~w z{uRsxJ{)7))9P)-6GaZ3&IVXgPT^S5hYV%GL?%P|Ie~)ea;5ZQ|9(2=`TT57DK(-v z5z4mubJi&8u62G1-jPme3gZqoj=ZD17Jv5PjhV0FDU&Mp_EkbY1k*iC@o5f@Bv;l| zkY;ss1}wJ%h+PV*H2uZvBmsrF8R2oEe=;$abO%VB%nvh3=8 zGR-=P9eR9M@0D1PN^j7S!3hoXK0vuad(~i%+K6M6#fbZ?S|^IMG|7vjyJ0Dhb|wb$ z9}hqAAi1FA(7ZiZ`2)=ZZvRfHa%B&r-#S0x&^e?7jY zs*gO-kArSsHg-y0>!tNd>cs1NdW4R&_LH^A#SSqVW-;n9dNVbk?@(imgXG6hLmRpl zvNc4(pq~|9Iy^x=A_U$&md*Hy3HPtY%*8kdUt5SaRm87K?^{&C)J`?{rr<+oL zsxm4)W;8w{HM`rOJO6!2@}9P^JcyCUnRvqQ&LW&59ZLP08+Pz|(*FI3q{vg+CjOsK ze1k?dh-FPPJ2ZKm(&hA->#X=iCJXr(e-$}?%zD7rd|5vp90zbPitYP zX*~YR@#e=@wC3O$Ma@OwmZMj{LQykW@`}F6boKDhh*Q1}8ad2^47)o==G#dVvB>_o zH1eO^guhlkr@I&9zcQ2+L;BvvlCq>~ZA4*Pz%&d-fN&R2%vlomMg~)3&NC^) zP9xM$&-+(=IPSJVNJy4ewG#HbAC}Sg9FFzhj?) z#X5c2^)96e!QAr$+#y~)IHNel*k1E`@7B3WU1UlA^YMgrA>H3fxM$e#XRgcB4!ijk z#D(MaYj;;n3hJ~E%&VPni}ya9eiZ-AhjH1Nwx-!f@n)2ahEU3>+^Z1@F@PkOzdwgT zUww7jb2t5l>9u=NI0jOyg5(BU&X}QAhR6VgzoGv0UQ;wusVm>N}M&dFOpTO)tcf2hFyvoQURz%jgL=L~+DI?We^s-<_xr34N25z}|b z=zVO=>zW;UH`L3d-e*FL-Ha=)1_)cq&FaF*CHSNsToFmv7=p?kz6CJI>d`(G1re`T z_#2gTcVW3CtqFyV6qghVeMy>#nuvSk;X(SRjDy~mZpyFJ9^xKT@)I0}#eSG5$0c_Q zpImyg-!ysb!taKhp~pgXJQT0LY(uRQaE*tIE<-w}aHs6m;eRwy;{7JU(%O+TA8T7c zf--%{av8>lpfYiG{mM+Z&U3ku4d3<;nxD(DxfO$KLUPS5Yav(RSGIbv@aj>8f2`_7 z;3KlGRg3#WgvzGk=mWOMitP=L_CvPiyt=0~@+%Zv7GO%s{v2Wy8s&yJROxb5L09C4 zO9e(9->!`}@P-MNBy5qM45m|mP!UR3h}l#MNR+K3q9uH$b4G23U^Z8^la{KzRsOEJ*P~K@@4`D7}CdPg(WXLX+F|-8@QnNC|((fPV{QwW)S;#ZrV^z%@s%bOvhuQ%j|cB+&_;azUo@h z$R?2NpmY+3uW7Cw^}ZiXrG`7P2=OxtSN0UEMvSsQ38Y*1Xt$k+PvgR7UTy28LGmV zM_%lb=ROAFH$PAk`kQpEu)PcM@Rr&bD0IDT-AnM7aQ&Z|&@5_n42(Bb2e|s%Tjd!I ztkNgCG0StjAEih`_{BAPOAjvAYtpbyj?R;*yf%3s{G?LrwB1&n)rIHT~18!KFhQzAG(;0*K8ePkf7v z43$t=b4HK5)f3MNNqrZMgy!^6KTJ9iiPa8?>Jq`%O_dP_bGw@*t0#6iU8^5HyrV>$ zAIJ&$_n&c;>-OfNS9sg;QJnwGK%|NZ!Tzo^eYfkBXeV9ijj-OQj+o%D!Z=-;HHkNb zmmh{A2jv_JG+;DeB03m1A9i*&H4!ON4AqSd(QHx_#-8=3ee7l-Ru()U0|p|7)&yy3!VgyS`WC)7jtoi;c@>3*tH{}ulGsUi)2}gcRF8Ic z^f3=|9twTibzfbINX#6aGc z!^A*^B|<=-K6gfcecaNc-26)1^})x=YO0;|Dn~EnYw%9!_bUgH=tELKyhaFElb$zy zTGu>@e;s}GJEHl`5ZY_lkEkfs`ugDJ#6Inb+fH$DlB}Iq-#ZPFIz>v*w{zAIGE+Pp zXuY?Igv+=B=5oEx@zgd5j(b;gZFcayPZXGul8OYlZWj|5m>ZGYDjJN674E8Z zFehf5E%te%7Odbt-TEkV;^CFpy$=V%TDtm^zhk!Eii3@{(QoY0(`ORf4#t~YgY)g4 zIh&k(tOn4krvfQS9+Ol0hIfFht48I)?s2D>QRw%3F_Nj5I;EtnWCm;b3;jB!kp=U) z>xkyBU$;y@73M+QN@%D~?Y`?H8jAD_`PIhuqDB>#9Y!O(OU*v~sY|v-tC0iMH{cnQzN)Pfw8EN%t%?Bfw zMhd$W>y{vi~pKT0zm+dWN;?o;XD3SscDXEasvpb-(2w^zku zSdMLCrevz}o!~l~W-m(F^r4r`x!w8n`Nyx^xJZt$KIdA6#%=m4>4MvDJzyWSS4fUR%9X>k?OqXxj z@Z_&7T2Dl5(56=sN0QY3b`#9rMzDaH8gQFX=gvocphKE%FV5%2W@B`h^J#WLcI*&Z zX}KtAFVB}9QDidT?^iCU)mp4!{y-ANw8h}@>2VOIa+aI2g)WRn4rR86=s7MCg>Y9L z%8OiU;r3<|$wsHZ8HI}G>Zks`W-gV!gDPjgt%XJT7ZmDEsJZLv5+{m7fTxZR^&54( z->}%@l?SiXy5yl=ZuD{}gSJe&mxo{f+V-Z;N|siommQHAUhE_H-{DkQp0x-?3cm%X zX4t2ygv*lSeqfy#-A1@1R3UowEx=TC26*3&y-4bSdG5@({G6HpdPL^=GInp%LU)Hu zWaF^h{s;rsugb`Lh+g90KHr&?`}bADykzzA6x|<2M#LI5v;}F2UH&c`uP6lHf<;Lv zBXY|vi1Hk+sjlnrw${nX%s4J1d4rtv`(}jk)Rfg&G9k`X=94a#iQJi%w(RAXO-X@l zOzz>oP7lq+HvzqjsfvRdRu%?wR1IVp`*&Sd)q;|0a|FF=6kGgJoRBxGIOA%*#Fg8g z+k*35^BaA{JN<{q;QWA2@z!cvnoX`Q*=%;9zw$uqcaS(^YS~vw17ZoiLc{6*7ak}x z+0yxP@JL7M!2dO?=lsyEH4m4Yt-xAiV>p$8W*W;+m$%=!2dr&57KRe3555bJzZqM) zL#%?-o-{r7_%0rAM>nBxnu+^yFbF4Aqxm3jp(5S=h9Ol^{$MqBTv#|_w983Jr<+jk z@Z+v2D26}nDji7aQx9|Ujp)mo8e)DSZguxkNbI#xfA^}33W=xm_?bMNsYoenNtI3{ z5Suik$iE~YQF}>hzA3RI-KKECY6Ofcro01d5qw=vN(E-xGY#u6G|#MdWm>!5?+h3^ zIs8A`x%O|i&p5o*y4AFG8!f7sOpB>|)m=^8$H8O-V^muem!vc`myBY|Bqc#zf}Ewq z5LvbAT9?%&qli|eLBhmc=CZg%M3Q~guiMW4fS&W7_kGX%ob#UZd@kob&-RpMeoI<3FhMtZL|01A%^{wIRzqYx|DbBfduaEKf5eCg@^lY8iI{9(OvS zB3p^>6~W{QzzH3x8SugvXaAo|IJL>Q(9_3d=|4W^Z|VX`X+?PB`=qA4Y3$^{KeG-T zj-!PCkzo3=4+}~bS_)q@7mG%r#Q}Znla|Z?aJVofTn*Z?2e-d5W9=xwT!<1)b+CSF zkG^Acy4aTMrl3J?DPGmty=lo$P1S3T9wga%sz@!E4%P^E-NU_Y-B!wuQ^en$1+E@~ zLF~UK+c;+RwGm&kk3B~40%qEX%aulf5oCD6hK^pe+C}@8{O-(;YF*7PMN~@5Qs)Gc zN4QBE5tL`&is_B!o~_~ai9V6QWayM2H$@f8BuZM0ePRAqixTn;tm?B@u4~zajj@{1 zu`qQ4(I6sVCr4Pqd*WO%@!El_^H{GaE^?=tY)o0KOEMFYGYROmm3b5jX*UyUM05}r zX=wcgRjJxiZDsI;Juq>i)||j;2d{eB@a9ADtc`PNP+h$UXKdne{z&MZt?C&lcxp`P^@!e*Mcs15qtx{^xeLPa(38Zo?3Ixwy|*H3Ag26 zEbZ$fJ&YYn)*Qm_ykxN)HBEGK2T%}aj~+cTX3i=m1YQamZy?9M9|%N19NRm=x0qr) zcBKueSori*fdSt)C2ry^Kn>Y7>hm*_Q;$a`w9 zpWigvnkBRJJ@U z1#Dp8af`Wo*HU8tOB&qXFOBiLDM9rn+X=G3tEY$=X4&(&A2)tpL?5>ap7zp2aS}MF zF0_w0MA`)jF%}YJepmH#ePLbiiH;vHs78*87nD02Ud5M*tS&K|c=Fl)c97@oaofH_Sa$QX z!f`2&iOmkH%Tl;@GGcoaa-B|{gGN{AlCJYDNrGVWg_W#PmV*etf-$QiDU_;}@B!h@ zec0NX<#5gOe7=N&d64bzsX|L+Y~-49t3G5Lgy|BbGXu9R>U#%2R>8Y`+WAB21?A27 zB;p-+$^A|{>|pg9-e&ssV|}s= zImxVJtp5`5L!+XUhO8*{4qM09!!CW7^QxH+Z-;W=Bj=;4YvxX1gfjO#oARhJffj&S2j5ij1 z6DF|8$=i<87C*OfzfrIyrUfVNt~pPue-HLJfAv)tHb-3_I8D81F85A)p!SrfX70V} zGX}9$5IE2Z|0_}Fl`}*PZ}U%t^H1jM56vgQP6=k`$nI2IEx#2->$Y*ju4>Vur6NdvHq^q6zb^%`??|1|a zp3pjiA~W-jAQMN|BS;0HcQ~uWyxZoTZQjMr|4)X!F1g5H2;-Jm4yfk(o*UT9iRu`Z F@i*ZEpSJ)2 literal 29643 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 literal 22801 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 W-FKg^bGCg43Sv)JKbLh*2~7aN3?W$n diff --git a/test/interpreter_functional/screenshots/baseline/partial_test_3.png b/test/interpreter_functional/screenshots/baseline/partial_test_3.png index ee9182a654d1e8590a02aa23d87abb57144a51a4..7b96f3ec43c7ed6cde24842fb49ffd41f02133be 100644 GIT binary patch literal 7054 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 W-lz9Dga5PXQMT{eb_F{4^}hjykH1|2 literal 7049 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 diff --git a/test/interpreter_functional/screenshots/baseline/tagcloud_all_data.png b/test/interpreter_functional/screenshots/baseline/tagcloud_all_data.png index 03ffc7ac7b1a58b38d4e54eb63ca198a3101021e..a7088de3849a54e103677f10d3d4224921e8feac 100644 GIT binary patch literal 11827 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 XKy)i_PxajewpesD4K>QuZruM5$4YVU literal 15701 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 G$o~LiX#uhT diff --git a/test/interpreter_functional/screenshots/baseline/tagcloud_fontsize.png b/test/interpreter_functional/screenshots/baseline/tagcloud_fontsize.png index 3a7315df405dfe11b32534e49b44700e67e60d9d..8f93ba81ad2adc2d9bfcd4645303607fd962a233 100644 GIT binary patch literal 10314 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 bZTAH~-nel&0XzVK!A_nCJ>K-q=^y_K?U1dR literal 13808 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 aaE4jCpDjfCnrb^JYCK*2T-G@yGywpYYsB;b literal 1920 zcmeAS@N?(olHy`uVBq!ia0y~yV41|gz^KE)1{9egI&&`r1G~GYi(^OyVv%M>FVdQ&MBb@0DHC3!vFvP diff --git a/test/interpreter_functional/screenshots/baseline/tagcloud_metric_data.png b/test/interpreter_functional/screenshots/baseline/tagcloud_metric_data.png index 5cdce6929667362eae577ab636fe34f789debb6d..98890b9687ac95a52ecf4a4299df070eb5e86fa6 100644 GIT binary patch literal 6712 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 mFo1ISpN??m3@2hhkpk)MYIF} literal 9163 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 diff --git a/test/interpreter_functional/screenshots/baseline/tagcloud_options.png b/test/interpreter_functional/screenshots/baseline/tagcloud_options.png index 394b5585097a24da5e3c10ed2c1b50bf8a9cc1cb..479280f598aef7d02121f8874c21c223c9f642dc 100644 GIT binary patch literal 15100 zcmeHtXH=7GyC!b8TSWyGu~0-oT4*XA1QY}WgwPT?h?@>lLX&O-1Vnm~Dm9P*(E!px z0VxR`LITtVNW!JmoIeecjiS5KRr`bF@sfG&D5l zR31IlrlI*Wl!oRQ|Ea&gl>!I-3>q4#29<{obe|tv{C3heE^y*-Y44uoP~@>=>^DxG z_KCPZh~J82J*K6C^)SGeBJHsxI_Z)k%(JgAuhyI5w={3GTr|Kps9rsN`sV3tv%gcy z($^1r(A?7&=3iIbhgi6dfq7_Xe)@EtKl%^Nle>TZ^Pj}C|Ji`M_zNAPF< z8P~JKl21JEllg0JtjPcEIscz+?!PC3ocmuGI-Vha5A>d(p?T3$4C3aeV7JXYizF+n zm}xlXuhU>E&c9DVmv6i8aaD+ziYb>~?$CY-u4`Tl0-wvybSmj7`^dl?3+q-sSq(3` zU~u*4H7K+_%YCkV$MS^7cU%B}-8&kG&I7hy*r=kX}*QAdZi;j%io@U#D)%W02Bx!@#|jSt{$XZxdd+*c4Q zjFwig|A8&_3u=K03&FXCg+a!>$h-!|D{q*VVli})Raxd=5Y_avC&f!&P`mh_Zuce1 z=`8PKb?7S!mSyyjbSlg`f?(e?%SUg&UR1Bb*jI>?JLuVyT5hLG_ASiY2~(@KbgWTsIH81j|X(GX~*w!L-cdc(oi=L3`Vl)87!EbY5kB=7@ z%KR%vRj$hzaGIA5iQK3z8nrFI^#I(DJeo#Z?tr3J(aSEOOY-$aXk)$Uqosi(N@gY{ z!76-zK<3QL9+%t=AC}FxeRCk=+PQ zuV2E|8~PT)73<4oCri1hpbXH|MjVaAzKV{(ew~O!yht!HX|TgoSF@4S6>aNK8EdR` zM=QDtt@q*e{im--EACl^5{#P4gAteZ7U#kB?bx7$77RR|fN_ zGPNDkQaqiwo&n7SKbq-caTQf7InoY4+~=7HBRCnBAl{ZmjJ6Uw2WrBmK>Gdi`^UaR z($7n@n`LiRwR55CN*4-3w4X=@J3V42537Y+vSx30H=Ao%+ zB_p^@mxBfY^3(C@6>#gYIeayuYmFk?oYr8Zf!$z_ZnKWi3&L0=f1xbyk$b9-4|JJKI;# z1xpnf=N;JUA!6TE8`petN-!NPQv+VJHTpdPUM_=TnC4Rc4KAeE*l_!+KZdN~13%~k z1TGbJ?vmF&$e8T)77=vJj5Xo~WHrRk(1I<((x7)nwI4h#zzo(PQb1NlUSLBLB_-al|ko^D&bWx7+aqJ&YiD07=HdRi!d57-7yu_zG12> zZg7Cr@dWd%sV8Rq5v+iWsU7@iVB!NHS@$fI;lBod47>N&e#=6{ax;lC9RA%Dl0|4E z#*iws=qWXMjq;~340P)i5{bE5aZ-ty}& zEi*=LUca^9oD?=|LE_3zV$wUOt+L1@p$f+Tx&(QD+f=2Ki1;-cLCR7p7u#aa9l44A zc)vC%qe|=X!Kv?k5t<32Y9hC*i<;t`4Ql%CDo>ZYgZ4wyoMjrHH@hn z<-v}xXk;|5t6IN-mf6=N17(1c)vDU`~6VEK6y$DUqt<_d1>aR_8 zSjRgCWhle~cXsC|kH<_~7UyScg_1- zXVUW?JH(6w6rrP2FHVvze<6vpe#u?pAjx6X#rydlS6m}G#Q}<``eHN!DPtc5EzciX zp7eO>sBvK1o_^rL;aA5cCJ|Lu`G)C9`>VT|zfUnf@^)O&Xus$FSZ6s*S8gafC63Q$ardlSdhKQZr;-u{O zh3tB_TrE9I$4D?65LMeClP@t^`ql(_XPf^$#;mD$vdDzQRy%~nf$T^HZ(tCQM9*RU zaG}NGOQ8ixCj%kN9qm(f=~0ttsiCY{#fcNB9iyra?@C)fNk3Nsbq#A!x<0vPU5^E+ zRWsmMbj~lB0LxU3d~XKVQv~3Q6B6XcN)*O->g7e?w3XoTV^$1==9SvZl62q;`3BjuGGy6=CwK2m|Gv+dTvl`P*tFWV3=R2UI!Ufr-en_T062ok$^g&UjnY*5W)95}g*m$#NrB zy|y9a2iu?k7USWR6OoLWbf8E-hM12|nNu|4YYKgwoJ*1;CkS_>_}ZFo>>nx|Vud}k zvoUUb$4otznC}`!Aznd{69gdVSE^KES}qtaE5P695i(+F6qC4n!8^zOWQD_$xUoir z;}3rHv8}$SUi`WWo_1|Bs&{qa8lK6=>9}N#_mc>id|p|Es@+h9FbE^t-4G7>`BKw6 zX3N++ViuGov%{el13GtzEc`$R3)yU1;;vMD0pA<(iq514_+1+q4 zw6U)Fl00^SjkPk*I@~#~@0-0Xet6U=QI%3AFfxw|-dylDEu!_g=YoZbQf4200Xw!P zUk@=DxX4d3l~Buxa^uheXe;^jDOfEb0a(&`#Dvg_{6Qs>iml37?tDfyHWDr{@S%U5 zNXL9ipkG9qC%B@fMaq24DjXK%k6t@(st35M zV}jL#o1q0vx8Ni*7Myq3lzZ7wBuRcOLpXzGFlP?~3ee&5Pl zYs98rFrdjeq3N9j%%s}U(Ia!lx;0~xbF2kQ+6Xa+%=uKGISmg1aXr#ZKqja`oOe*` zb^tg?10X#m*jS|bvA50S;^ONP66$>q+$6b;0%fW^(f&gPrK7ftEHJFFco8vY<`vvh zR3I}%_ANzFC|Nxa)U;5;(nmfzxR%r)wTo^~8~+5Ux@HbimB-Uah|_+0h6E#Yzq7Yv z)K*7sZSP?}RUW$yw!<#=FFiMnfs62gu{~3wiuv8>|>4ah6DN-W3%+ zM~hT>2f`1S&4c zM@Ob#kks)qtIw9i?)Q8$@4D@vejr&rh0F8MW&6eQnF35b(o_NqHXH>ZIw(q*qzGKv zP_e=+-ZAfezzaw6R-ts>r`gSA-C2q#)o?_Ef)FSBr!;9Gi<^1W@V>5L;9ogOam!ani@d_y;~j-C64+r?5aBL&Cs_@Ul$pekE?>-4q7-_f z%%^k*e}?lRh@ECgxcIXiz`VMQlS zA*7|BE99JleP2fI3?sJho(ow%peI%Jh!2gKb#x zyo@uEZXl1ojgNz5w}cwsSZrO%QnuWec^-5V;x%}i6YgeE^AKcrOY?1uxRlhK%)X8F z1f7Pj81D>4qr%$fNB~u(+rDX)Z%Df1jkdc*BIjtM&}UUz=^yuWn@^GRL9AMaMfAGv zT|}5(>`2jk*>Drxmn^xKCS%edjzij>Xg|a#F$m8yGF$fbl2lyYuU1hrc&1UolR)(g$`iS~F~{x6cHn72rW-ax%lNV`~rwYQ>x88gLpBjLJzLhC%} zQKr}I7T$Z8x+^0tx4)7v0jNpK7ip1a1B3>Mn2JaEW~HwjYNtJ4`YBuE;hg@3%9c@N zE{eF!P*#{g!n<0>en>~(7phWy>NJdidI$<7k$3H($?yAsJJaXPj`#Jd8?`bh*bnqh z0*D(9sqm^%901e&<;+f9p^u@}4q_nHBYShYb#y<7 zo}-H*f#%ANSzGRAw%Zf zEL|b3t*fA{Jt>Tm-#wQKH~wkcpyuCre6dSW&VE!LDm(?s%wqki*#??#3pTS&wN!SP zg6=k{lRB^oeO{!eUQYq-huE^ylGFl-BHff>P`Fa%N<*}5p?F0G*fHdcWVn!?u(p@y z*3YC#^1AEfTg=SPBdyXUGeQ8Jq%6HR5%ph?GGHY>(o@t=@YU#L5(AnPj|}LnKFZhh ze~C%aury5|shI_Ea)XZc)vSMk=X?Jw7b?>nU^`GTvJN+z)94rBd5HAU7Q&WDA+R@< z9~YR~bR*Netvcz3Ca2tZWYiTU{bdxc6coS#I_Jt)}aHkL{V_7H39pygEEvX;4>ktN@XKAH0Qh{FZFB8Up%RoULgZCFNdzmtE zt>E6?SdqI*WA<+r9?!TRGQ1zf>k(Eq(RMaWtQo)F|B8M z{9Uyr*tLi2owK|k6Rxl&-hyhfqM&-D^d3M+TLD=gLnLU>MlwK!8QlRrNX=;FYj*6P ztvXp{1qdtCG-LlCm9IhJD6IctTA7#mW_KG#wR%rmm6)1?$4o4MW_bwK7O4&l=>V;q zHYVOj2Y$;jrZ+{HyU&Hp{_K$~F8>@;>->;aVX5aYo1+yY0M0>H9eY1E9UGU9Tf>7p zIq&@*jR)O?8+WwE`)#^~4^<)sSNwf6m%*GE&>pDrNlL5z$ie+3bHkHKAT?`hKzKTY zj_-=?#E=du1e8Frn`wqoX`@GOV7?oMz%7XiPmVn%!ZE0@|owZs*RN9&Ej6D ziU!M#yV60?^v0~wve;d`RB)0q&J79%dN>$401>guC|+z!&S@rtvf9hkIU!G=W4!e* zcMU6$T^KgvB;DhAxcm@jT7dmKH?Kt7X{H4OFC6~&8h_BS;aXr1>I00te&0a60a+9W z_<-DK1>(1?zkXU`rC-eGHB)rjqFAyc8uWj*znbDyYd&NdU2}t*6qW}>-gB|Ccn7#C z%6fIE7bH&W{P>IeWN8+ubaw?sm1{BvIaG5uAsM`146Pb?uVgftc6C$B%l5oJ;(t2v zf&u5F@`FQCeia~#7&d*yoYL%BnlVA{yTTS>5jq=`@6eQ!1=Y?_nW|Y|df>(GG%3Q! zJ+GA8VLhg)Rm&=CD(ZVM-IHe*Ss-X(ozFurZga~M)0v*%bG6hmyx?py6f%pDI5rxn z5uTV=47x{kPKJRBK*HIUM=@_XPs75~mv=#W3h1~1um!B24C;O~ZOKTSxJwd<(fm&> zm~VI~PY#_jynPps0Vws9&mJFCC!c!6Urv`1z=Adu900{0DPdK*tiNd(LCiJGnXdJf z1gYy@2mFXYv9Jm6ZwtK*V8dL^HCOA*E)q!+Mjm3}!@CI_hZj6W^)5Ehkp6I7 zyr7Q~W^GCG`2GjvrhL#OAAD9%d;iD-M>axXXV(LtKXN(RIsY*{5 z<`#?JEtOlsIFh@%T-Lq}ffku?q(-kqK~z{8QWoy1JD%soG7Ja(zY?4rfQ1K=mdW*kLhussI7$c#R`cNC_^>U)QHV)%%jdFwOEqbum{q%^h{yVXh`pLtni*3OEH@U)ruI<&%m@na$$G^97j};pjp4? zA|nL9pvG|N_N+qOLrB}eXpwFJ7gq&ClI!K-&J<0R5|hvO0j{fF6IL7-ONPa8Uo2}) zz5Fc$Gc$z^wThY6++o&2r>WXC$Ei_jtwPpV=qlXIs&tL^&gr>G6&Yr8%nw+&yA3`+ z8WvKE!vLeeWcQ$)2-cf!=Y~pD<68Hc=~`2dD>Th{JQv3#k4i?nsFxW51uhn}BcGln zL^FPQl1n>1K0Lh+@fa*N!IEk_0JR35SE|5>quZ{4O9PcKt}hhGJ>U@_)qC^f^J~?> z?xs76+YJ{yyx8#{{A0`2k#b|yK;+i-f)QSy`Yed-BlS?IX+}0~bPxgqbZ0ky4wJHr zI&$(c6lFjSM@=AzEnmd~&aM&mQ`2j5wXqPI18_CJD*&120pqAx2W-AF6)?OOyY}y{ zm1Cf|c+j!r7)iRwC^X;gap$YEA2LmMUlIVZuyu6m@dn^l6p31GYyvC`6#9GJPg)&F zCYOYQ9dXsK{-`J}{C#T7G32;%YpOtkAf^NysKhDhmfnWs(H!$Zhe~j)QPYR10Vp{J zoqylIaM;JCibMrqh!;5K;!U6t zs;Uek^(`U683kBE0mNH-ydBLl3tm+NHcOXb4mbwJ{|TcP`)H>bx6)%xAdu5iHv#o4 z_wlN+xCl)fU0htUK(S=p?C*Bk(8g}sF^%Fpaty=HGXWTNq z1*P(Sz99EtxU6Q4{7+3$=X9BXqChiR@1r%garjvQzdNwnuxtKMN7C=om>QenRu4E& za^FcNbRi5 zsQ0fC(wd@(>OPFato6M($2Z+E=);^Rk}GDD4OkpF=lKdb>ke0cL?r2N=`sS$*5aK; zcnS}ETAGD6Sx%>2E*+g&0*%VcRS=fVy3QitZJ@SxWxMSuemXlO`=`1$hXRv!s-#u}mD z_Jx|HkINX{0oFRWotYoxXqZEujnPf1V>>hqklQbXPAouWLD+voqh{m!S>3o7Ota!m z9fmY;EQ1`76bZ;rj1Fkr0(ZCV_Q;ojNUWs=Xn_fE z3Njn)V0gR8(7W^CLKi-DTy`xSe`XDlLJwylvC%Ih(i(1JQ;#d>1NOb_Rs+tZ$8MM0 z+^G&l0S~^n%;uApGgHi;pT)g%(E*!r-WcR%?3cj5RBZrWco7VSC)ff02YU~6>%PzQ zwktoo*B&}PcnKY6F(L#WdxrfevB5%xzeILv*a&C`P|SO+dAHsI>!fc~66q$M^dQ=4 zE>&Vc#h--E2|*lNil2pOd-Nl~dH@tGa{(#`718@!-3-mo2Lh-)K^AzoIK|;f0R1l0Ct0j`6T7N z7)xu3&;Az5TVk?nUXp-t~b)@xb=<{FGO|jA+u@&cAh_ z%8@^xdqEuu)uFf_47V)^9rW@X1I-cj4@?V&y0!xg2Pe6B?t7Vl{T-+s8F3`eS)$&ukHxo;f($RX~2 zL12EG97rPg82kQQ`VH*HsIf^WF@_t|IX{0{6(mUY$c*2@wWh}bm!Up6IK@athZ{j} z9m!T7W9tw0$mHp(Kg?&x74QH?vFn98iOOx_d+SBs^3`b}W(`$I>`|N1QqVcGlJuF|2%F{eHB z1Rk%Fq$?+%W^+{^0iXanKHeo^j_iKKDd}(S-jYnDnb>GlXE0gI%6^1)FG-IK(Uo ze7)lH1au1jVkI8h10LPHV8Ap>Mm_)1I8)itX4?XmK5ZFnm-V?fmyK6RD zKuKFH+pCL~mJP}{oN$NYh4AfYY2M`zIJ_upiM)`F$VV}hQqwJK_m%u55~hN7Br&MdW(2=q8m*e*>k6?$ZlAj1$^A>KLiv+r%l(NtDYjDVlpkPD%o z$B@~fpBOMW^z+r?zaIf+_;0)X{~ZipS*Mmff9F)JUk0k>M|P;u(Ns}X+=`NBXo~0; zuGsB$Ev$r}{;g`_;g(ABr!!?Yc#$B#GN+ zM#%ZXHC$%|`^;D(GnANK(> zv%Q+N^)r3gPEGRkbPKsPUACw-rin;y3g@RXOQ=>7pX(c=1>ayNQp3xmVxl)s{xis9uDOY#DX7?;YL*u=1+W!1h(mmVi z(6wFW6_~7fZHoVDUj!BWLEv@S^Oii=wyx{zNHuHy{^JMS9w``&!$m~L=!iH>Ka}Kj zG!sHEE;>-l1Ky^{K3_Rk>NKFF0qi=xvHRoj>!pLFPK(nC~E(|-Gy;x=3Wc5Zt9}ULj!{$lwE(xXW5-Ozl!PES*%g# z143tKLT`f(TP*26SvWxlTGF%ePsUSRvIW!Amn0Fm%a}OgEcTPu-&_l$73(OB&ffK! z{VFrQ&Cltr&;)TLBd35H=*Y+?e)|(XsB3b|$5N&Ilw4;8KvNTe{ond1Ss zrpXsU2x^#QW^MG#nf7M$%5_1n8T2+Wfsr8VpbRQ`OeZEvOWa31WT+eKsF2WQ4k#Ny zwj4rS)HC1gkfJEbLMM5!O1eV6G*+070&S^9*$8=KW@Kd{T>M9j8ctRrE;*SGeOVx> zb-uAxr?Rf|wt@SK=p(vd1woK4HZui(R@?)_C#_DPVf;cu@G+lrNPqv@g4}!i<+OX< z@U(bh`tLP*&NhP^=t_5cJ_(*j8WA$9u{}LSt(=uca!@R{I+hXV+sl3oFgw+9!>bRQ zs!+7F7#RA2LbKg$2X6Y(Wu%D)a0g}FJ~G9QgyBtS2#z4kPrm=)_xjQnwJCX})o$?Z zX##-|Pt0ggrbd*F$EdlL9YVoDRAvjv4Qu6H>x+TQpg}BD7*`}=c#?sZdE(?r+a-)5O0~kxKp{9{zWIz$FfRX#$xczbY0Y-CPY*Q!M$AK4p#hiMW8T@> zwX>eoW9q7lXnLOxL;w7FqtK-Ekp^#qp#9vh)m?u7qBQTd(~Pr2)@gkJf5|^@ltDL{~g$w6EB*rBqpy9Hqg>tpKM(rtaHxe36e5PY>TW1thdMp*Z zK1pw1zugVXpX*?C-``fLC@`$i*xA`ZsgBl~3IZH)JMhlc*6F>(#FUwml8oBjI_ZRY zmW)JsFDk?HH)SR&XkOB)g|qc%!9+&Hiu{F7kgcZ{8;g z32QqP{pXRndJ8&dD6?`t^2M^rdUfxd25d=*-lmF z!1C9x2-*>w$ZPBCz3)@2He%9c_|Vzeu9R^BLx7Zgpn^fb4+_b)6Hp$U6CkA2Hb-~f zYUQnTjkWUK&M$BrZ$nV+G9XmQdT@NtuCK-1dw~ttnksJgJH~k2Z`LVkzl)xX_x)~H z@$RaazM$MrH~mJ3-0#A+w#NpfLL(y$5>_vU7#P-yvg?u1R(^k7XR=6!NfxGbhe2t9 zln}rX5Fl5PA{%oHJ=dWH!2`b1OIS}{p&>MUOo0IF3B)HI_L>y@WBh*!8rv#QHFuPbBMg| zk1yjGpREtJGiwQ#w%t1gyQkflHClgO)AT%X+*@31eQt16Wc7aa>wD$#KSb(=e&1~g zy(?Y3E_8*Sj&FP^S$aeB&+gauM#r-<4}zY=J9ly;EknRcNS;(8I-R z;?mA7wTqi7GH>kpI~**Cl?br;zU?otWw;dfU4C79<)`k1ZBcXEHJvUlc&Pbqo0pAb zmFxp%X)fAlyL~E+?M98I4)7nXZA0t%cB}Ogm4U(LR-g6r!b_Gu*c{(g{20#6+`bm) zq+@K{7QVK+`oJsOmAiz2`-}~VK!5YidHKFJX7JCXIL2#TI$uM{>N1I!pTDsa$EjwT z+?md$p{UZ?!Y;#chV$OOmZ_0Mg1s&C;9tf2e{<()JbA+G*jQN_va$60Y+xW-(hL8B zQ*FusFLK?obNQ@;7_;Gj8m{yLBWuIJ9-U^)l^{8|ulz+-Ma2`Udz)L`%eD8l%W_|6MwOw21Cw5CUeY;N+pCy$qxPb+bRSaQvE zl}hF0=8J8wIR77V{r&%zrO+J16|B+=R!>e}}Qxx_xS6UU+(DIU_Ukk77Q(BJDbV znOL~o0ZTDpL)xqn+!4%i@s+1@%F7d}t;t?{W2HPb9PF**A40{fH+9)}HzutP+(goG zTden0R5aLce`Wh_E^((=pWj9W+n-S_;V-gPdhV9Hk&^D)G`6QzpCUq+aIx>RYtXOSe}8ABEc2eFfrPy4x@tbV?zwP9pr z)aSn(>r{7;wo?21m?d=0)e6p;2^Vryy8l9MZ<8&%x|*dJx4DcK{PWLk9acRLLD6|q zv2=~M2l~rXuE*xUzinI^A2b}7uV0E7QQY%*mjAvvCiuhmr$+|+EsX@B_15U&Bj@v~ z4x@jRoVg-2c{@eoEH`0zOWXOX21^hFr^tr6>~PXMq@iKx(ASpPE->DEgR)<@OKgQF zyP|cze1se%2A&L_uu$BW-rn84d)HecoLN-9!fpPp>i;tIa7x9Q`OzG1OG|R!^v`cA zU4I%P455@by3-SkLa>@rfq(UuyKuygrTYd=k}bdU!=!?W#@M%={0}SM9-OS5 zI0L`#;(Db!$KI(Vs=GmptM1b4Xb>w{J+-c*g-ka@^zaA?HJeMgT-E4EulriF_2nr@ zyOPYzr;8qDCC6T;DKJaJ1 z&wVn}?F_v_vKR-QfTZP_(7FKoSP)^EHTRy;L9Xr#%uG1RNr(D7wy)}E) z;H-^AzHe}Tdbz8K&2q5o8^2N1Ti}pHQJbHy+pVSuaabEFWe7N?4ar^jFzlLmv?YzS=DkCk7`h-=EX|KAIy_nS2{p+AiBoBE7)$yy_RTgYa4E1i__R9qY`+`ian`;i z#o=;|RIt5QwI01yTT(EXr_VyZ%?64W#5tyI=lLGX*b5E8Pd2Hw$9Z^}<(~X1jxtso z|FN|u-^Z432V$$Ft1H-cxa72TXBr3p{%H)8#7Cjfv1K(atveB0*B&CWl<1UId>76s zz4wob;XZS;Zb7qm(dX;_44%j?C}0VmXypGGE>}7+cj?{trywa`8GJsI$XEr$+>=sx zr{51K^@&;>09hsh+k(P!T4ljTv%Pm~4%3@Z@I>@Y1cRkmVR0GMyHo}9?BYwOv*o@UfSs8%c^;gm@kNjX} zZ~@?kCbt$fOg1Aw8U2NS}t#Qiv{REff8ef|P}&l6jo zi!a0+TAuV5gf?3hXSmazYnt-VGKw)}YVH{@`$i;&&J5sBNE+mqJY#+_<5D%pWc5VM ztLM3x<0JVq-gC!d2MvUD7=(oQ?2+HIfRh`ztG?)@{`#fd{ntj=eP-!hdK)c{AoKqH z4r$H5M&f4_t2NJeU$l zJjZ-DQ4~A*dC0*gRsQvAxk;kesGwm<`5E%&2y?Nu=U?I+&86W=;Y^v&y}XWW9Z;;R z3yl5d{6Jw|UgGtd-7K)MH`@Wu8*_I?(|?Df)0y6W*{rz~U-;-D7!P_<{y7KuICay1 zojv_}DBgKh8?0CYl%5kO(3&YS*Aj&>^`8%|)=+4Gqfy?RkNYpU aHE&iz8^0!7DlG?zEGmi`4~yiVy!s!XBR4+) literal 18998 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 V8LWggH9(gQQeyINi$(N5{y#)d+qwV% diff --git a/test/interpreter_functional/snapshots/baseline/combined_test2.json b/test/interpreter_functional/snapshots/baseline/combined_test2.json index 98c7844e41f19b..84203617ff8535 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test2.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/combined_test3.json b/test/interpreter_functional/snapshots/baseline/combined_test3.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test3.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/final_output_test.json b/test/interpreter_functional/snapshots/baseline/final_output_test.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/baseline/final_output_test.json +++ b/test/interpreter_functional/snapshots/baseline/final_output_test.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_all_data.json b/test/interpreter_functional/snapshots/baseline/metric_all_data.json index 26f111e9edcf92..9b0122c1574812 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_all_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json index 7f64f978451915..2d6e756a7f0a3a 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json index e171a65be8bab5..37c6885d76cb08 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json index ed8b0b258fd90f..60a0e450906a27 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_1.json b/test/interpreter_functional/snapshots/baseline/partial_test_1.json index 8a349aa5df0600..6b2f93b47c0b28 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_1.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_1.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_2.json b/test/interpreter_functional/snapshots/baseline/partial_test_2.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_2.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_2.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_3.json b/test/interpreter_functional/snapshots/baseline/partial_test_3.json index c1e429508c37ff..4241d6f208bfd4 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_3.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"region_map"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"region_map"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test2.json b/test/interpreter_functional/snapshots/baseline/step_output_test2.json index 98c7844e41f19b..84203617ff8535 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test2.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test3.json b/test/interpreter_functional/snapshots/baseline/step_output_test3.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test3.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json index 1325c7fbed03ea..ae1e817424cb10 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json index 2b063b518665af..c0da4794728807 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json index 6152fd406961fc..c5fbcd63b06854 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json index e4c6b09a264ddb..b67b0744494034 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test2.json b/test/interpreter_functional/snapshots/session/combined_test2.json index 98c7844e41f19b..84203617ff8535 100644 --- a/test/interpreter_functional/snapshots/session/combined_test2.json +++ b/test/interpreter_functional/snapshots/session/combined_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test3.json b/test/interpreter_functional/snapshots/session/combined_test3.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/session/combined_test3.json +++ b/test/interpreter_functional/snapshots/session/combined_test3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/final_output_test.json b/test/interpreter_functional/snapshots/session/final_output_test.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/session/final_output_test.json +++ b/test/interpreter_functional/snapshots/session/final_output_test.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_all_data.json b/test/interpreter_functional/snapshots/session/metric_all_data.json index 26f111e9edcf92..9b0122c1574812 100644 --- a/test/interpreter_functional/snapshots/session/metric_all_data.json +++ b/test/interpreter_functional/snapshots/session/metric_all_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json index 7f64f978451915..2d6e756a7f0a3a 100644 --- a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json index e171a65be8bab5..37c6885d76cb08 100644 --- a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json index ed8b0b258fd90f..60a0e450906a27 100644 --- a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"},{"id":"col-2-1","name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"},{"id":"col-2-1","meta":{"aggConfigParams":{"field":"bytes"},"indexPatternId":"logstash-*","type":"max"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_1.json b/test/interpreter_functional/snapshots/session/partial_test_1.json index 8a349aa5df0600..6b2f93b47c0b28 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_1.json +++ b/test/interpreter_functional/snapshots/session/partial_test_1.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_2.json b/test/interpreter_functional/snapshots/session/partial_test_2.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_2.json +++ b/test/interpreter_functional/snapshots/session/partial_test_2.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_3.json b/test/interpreter_functional/snapshots/session/partial_test_3.json index c1e429508c37ff..4241d6f208bfd4 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_3.json +++ b/test/interpreter_functional/snapshots/session/partial_test_3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"region_map"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"region_map"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test2.json b/test/interpreter_functional/snapshots/session/step_output_test2.json index 98c7844e41f19b..84203617ff8535 100644 --- a/test/interpreter_functional/snapshots/session/step_output_test2.json +++ b/test/interpreter_functional/snapshots/session/step_output_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test3.json b/test/interpreter_functional/snapshots/session/step_output_test3.json index 310377eadd165a..af9fe198d88ea5 100644 --- a/test/interpreter_functional/snapshots/session/step_output_test3.json +++ b/test/interpreter_functional/snapshots/session/step_output_test3.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json index 1325c7fbed03ea..ae1e817424cb10 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json index 2b063b518665af..c0da4794728807 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json index 6152fd406961fc..c5fbcd63b06854 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_options.json b/test/interpreter_functional/snapshots/session/tagcloud_options.json index e4c6b09a264ddb..b67b0744494034 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_options.json @@ -1 +1 @@ -{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","name":"response.raw: Descending"},{"id":"col-1-1","name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file +{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}} \ No newline at end of file From c76519e15c4ca10c9e2c7fc5b0dcb8216d7661b0 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Mon, 3 Feb 2020 14:02:28 +0000 Subject: [PATCH 61/69] enable darwin for the node installation in the CI (#51705) * enable darwin for the node installation in the CI * refactor: avoid hardcode strings and customise based on the OS flavour * fix classifier Co-authored-by: Elastic Machine --- src/dev/ci_setup/setup_env.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dev/ci_setup/setup_env.sh b/src/dev/ci_setup/setup_env.sh index 5217fdf002be9c..823c70e80fe7cd 100644 --- a/src/dev/ci_setup/setup_env.sh +++ b/src/dev/ci_setup/setup_env.sh @@ -56,23 +56,23 @@ export KIBANA_PKG_BRANCH="$kbnBranch" ### ### download node ### +nodeVersion="$(cat "$dir/.node-version")" +nodeDir="$cacheDir/node/$nodeVersion" +nodeBin="$nodeDir/bin" +classifier="x64.tar.gz" + UNAME=$(uname) OS="linux" if [[ "$UNAME" = *"MINGW64_NT"* ]]; then OS="win" + nodeBin="$HOME/node" + classifier="x64.zip" +elif [[ "$UNAME" == "Darwin" ]]; then + OS="darwin" fi echo " -- Running on OS: $OS" -nodeVersion="$(cat "$dir/.node-version")" -nodeDir="$cacheDir/node/$nodeVersion" - -if [[ "$OS" == "win" ]]; then - nodeBin="$HOME/node" - nodeUrl="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/dist/v$nodeVersion/node-v$nodeVersion-win-x64.zip" -else - nodeBin="$nodeDir/bin" - nodeUrl="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/dist/v$nodeVersion/node-v$nodeVersion-linux-x64.tar.gz" -fi +nodeUrl="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/dist/v$nodeVersion/node-v$nodeVersion-${OS}-${classifier}" if [[ "$installNode" == "true" ]]; then echo " -- node: version=v${nodeVersion} dir=$nodeDir" From b64f0a76fd4eda536f6fc0cda891a45620249e9c Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Mon, 3 Feb 2020 15:33:57 +0100 Subject: [PATCH 62/69] [ML] Setup apiDocs to generate routes docs (#56006) * [ML] setup typedoc to generate routes docs * [ML] remove typedoc packages * [ML] apiDoc * [ML] update optional params * [ML] address pr comments * [ML] change names * [ML] change description for GetDataFrameAnalyticsMessages * [ML] add custom order --- x-pack/legacy/plugins/ml/.gitignore | 1 + .../legacy/plugins/ml/server/routes/README.md | 16 +++ .../plugins/ml/server/routes/apidoc.json | 21 ++++ .../ml/server/routes/data_frame_analytics.ts | 107 ++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 x-pack/legacy/plugins/ml/.gitignore create mode 100644 x-pack/legacy/plugins/ml/server/routes/README.md create mode 100644 x-pack/legacy/plugins/ml/server/routes/apidoc.json diff --git a/x-pack/legacy/plugins/ml/.gitignore b/x-pack/legacy/plugins/ml/.gitignore new file mode 100644 index 00000000000000..708c5b199467b9 --- /dev/null +++ b/x-pack/legacy/plugins/ml/.gitignore @@ -0,0 +1 @@ +routes_doc diff --git a/x-pack/legacy/plugins/ml/server/routes/README.md b/x-pack/legacy/plugins/ml/server/routes/README.md new file mode 100644 index 00000000000000..1d08335af3d2e9 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/README.md @@ -0,0 +1,16 @@ +# ML Kibana API routes + +This folder contains ML API routes in Kibana. + +Each route handler requires [apiDoc](https://github.com/apidoc/apidoc) annotations in order +to generate documentation. +The [apidoc-markdown](https://github.com/rigwild/apidoc-markdown) package is also required in order to generate the markdown. + +For now the process is pretty manual. You need to make sure the packages mentioned above are installed globally +to execute the following command from the directory in which this README file is located. +``` +apidoc -i . -o ../routes_doc && apidoc-markdown -p ../routes_doc -o ../routes_doc/ML_API.md +``` + +It will create a new directory `routes_doc` (next to the `routes` folder) which contains the documentation in HTML format +as well as `ML_API.md` file. \ No newline at end of file diff --git a/x-pack/legacy/plugins/ml/server/routes/apidoc.json b/x-pack/legacy/plugins/ml/server/routes/apidoc.json new file mode 100644 index 00000000000000..8292e946cd344d --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/apidoc.json @@ -0,0 +1,21 @@ +{ + "name": "ml_kibana_api", + "version": "0.1.0", + "description": "ML Kibana API", + "title": "ML Kibana API", + "url" : "/api/ml/", + "order": [ + "DataFrameAnalytics", + "GetDataFrameAnalytics", + "GetDataFrameAnalyticsById", + "GetDataFrameAnalyticsStats", + "GetDataFrameAnalyticsStatsById", + "UpdateDataFrameAnalytics", + "EvaluateDataFrameAnalytics", + "ExplainDataFrameAnalytics", + "DeleteDataFrameAnalytics", + "StartDataFrameAnalyticsJob", + "StopsDataFrameAnalyticsJob", + "GetDataFrameAnalyticsMessages" + ] +} diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts index 7b855e5f87cbf6..67fa2fba46f1a9 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts @@ -15,7 +15,20 @@ import { dataAnalyticsExplainSchema, } from '../new_platform/data_analytics_schema'; +/** + * Routes for the data frame analytics + */ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteInitialization) { + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics Get analytics data + * @apiName GetDataFrameAnalytics + * @apiDescription Returns the list of data frame analytics jobs. + * + * @apiSuccess {Number} count + * @apiSuccess {Object[]} data_frame_analytics + */ router.get( { path: '/api/ml/data_frame/analytics', @@ -35,6 +48,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics/:analyticsId Get analytics data by id + * @apiName GetDataFrameAnalyticsById + * @apiDescription Returns the data frame analytics job. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.get( { path: '/api/ml/data_frame/analytics/{analyticsId}', @@ -57,6 +79,13 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics/_stats Get analytics stats + * @apiName GetDataFrameAnalyticsStats + * @apiDescription Returns data frame analytics jobs statistics. + */ router.get( { path: '/api/ml/data_frame/analytics/_stats', @@ -76,6 +105,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics/:analyticsId/_stats Get stats for requested analytics job + * @apiName GetDataFrameAnalyticsStatsById + * @apiDescription Returns data frame analytics job statistics. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.get( { path: '/api/ml/data_frame/analytics/{analyticsId}/_stats', @@ -101,6 +139,16 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {put} /api/ml/data_frame/analytics/:analyticsId Instantiate a data frame analytics job + * @apiName UpdateDataFrameAnalytics + * @apiDescription This API creates a data frame analytics job that performs an analysis + * on the source index and stores the outcome in a destination index. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.put( { path: '/api/ml/data_frame/analytics/{analyticsId}', @@ -130,6 +178,13 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {post} /api/ml/data_frame/_evaluate Evaluate the data frame analytics for an annotated index + * @apiName EvaluateDataFrameAnalytics + * @apiDescription Evaluates the data frame analytics for an annotated index. + */ router.post( { path: '/api/ml/data_frame/_evaluate', @@ -154,6 +209,22 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {post} /api/ml/data_frame/_explain Explain a data frame analytics config + * @apiName ExplainDataFrameAnalytics + * @apiDescription This API provides explanations for a data frame analytics config + * that either exists already or one that has not been created yet. + * + * @apiParam {String} [description] + * @apiParam {Object} [dest] + * @apiParam {Object} source + * @apiParam {String} source.index + * @apiParam {Object} analysis + * @apiParam {Object} [analyzed_fields] + * @apiParam {String} [model_memory_limit] + */ router.post( { path: '/api/ml/data_frame/analytics/_explain', @@ -178,6 +249,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {delete} /api/ml/data_frame/analytics/:analyticsId Delete specified analytics job + * @apiName DeleteDataFrameAnalytics + * @apiDescription Deletes specified data frame analytics job. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.delete( { path: '/api/ml/data_frame/analytics/{analyticsId}', @@ -205,6 +285,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {post} /api/ml/data_frame/analytics/:analyticsId/_start Start specified analytics job + * @apiName StartDataFrameAnalyticsJob + * @apiDescription Starts a data frame analytics job. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.post( { path: '/api/ml/data_frame/analytics/{analyticsId}/_start', @@ -229,6 +318,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {post} /api/ml/data_frame/analytics/:analyticsId/_stop Stop specified analytics job + * @apiName StopsDataFrameAnalyticsJob + * @apiDescription Stops a data frame analytics job. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.post( { path: '/api/ml/data_frame/analytics/{analyticsId}/_stop', @@ -263,6 +361,15 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }) ); + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics/:analyticsId/messages Get analytics job messages + * @apiName GetDataFrameAnalyticsMessages + * @apiDescription Returns the list of audit messages for data frame analytics jobs. + * + * @apiParam {String} analyticsId Analytics ID. + */ router.get( { path: '/api/ml/data_frame/analytics/{analyticsId}/messages', From 7dc8c6f9ba15d4566147dbac144b32becdf2adee Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Mon, 3 Feb 2020 07:51:53 -0700 Subject: [PATCH 63/69] [Uptime] Fix flaky functional test for #54541 (#56449) * Add timeout block to race-prone functional test code. * Add timeout for pagination click functions. Co-authored-by: Elastic Machine --- x-pack/test/functional/apps/uptime/overview.ts | 12 ++++++++---- x-pack/test/functional/services/uptime.ts | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/x-pack/test/functional/apps/uptime/overview.ts b/x-pack/test/functional/apps/uptime/overview.ts index 73b91a61196bfa..9a879032fadc14 100644 --- a/x-pack/test/functional/apps/uptime/overview.ts +++ b/x-pack/test/functional/apps/uptime/overview.ts @@ -53,8 +53,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('pagination is cleared when filter criteria changes', async () => { await pageObjects.uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END); await pageObjects.uptime.changePage('next'); - // there should now be pagination data in the URL - await pageObjects.uptime.pageUrlContains('pagination'); await pageObjects.uptime.pageHasExpectedIds([ '0010-down', '0011-up', @@ -67,9 +65,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { '0018-up', '0019-up', ]); + await retry.tryForTime(12000, async () => { + // there should now be pagination data in the URL + await pageObjects.uptime.pageUrlContains('pagination'); + }); await pageObjects.uptime.setStatusFilter('up'); - // ensure that pagination is removed from the URL - await pageObjects.uptime.pageUrlContains('pagination', false); await pageObjects.uptime.pageHasExpectedIds([ '0000-intermittent', '0001-up', @@ -82,6 +82,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { '0008-up', '0009-up', ]); + await retry.tryForTime(12000, async () => { + // ensure that pagination is removed from the URL + await pageObjects.uptime.pageUrlContains('pagination', false); + }); }); describe('snapshot counts', () => { diff --git a/x-pack/test/functional/services/uptime.ts b/x-pack/test/functional/services/uptime.ts index ed39f28aabbfad..1d8e0c97b99c4d 100644 --- a/x-pack/test/functional/services/uptime.ts +++ b/x-pack/test/functional/services/uptime.ts @@ -38,10 +38,10 @@ export function UptimeProvider({ getService }: FtrProviderContext) { await browser.pressKeys(browser.keys.ENTER); }, async goToNextPage() { - await testSubjects.click('xpack.uptime.monitorList.nextButton'); + await testSubjects.click('xpack.uptime.monitorList.nextButton', 5000); }, async goToPreviousPage() { - await testSubjects.click('xpack.uptime.monitorList.prevButton'); + await testSubjects.click('xpack.uptime.monitorList.prevButton', 5000); }, async setStatusFilterUp() { await testSubjects.click('xpack.uptime.filterBar.filterStatusUp'); From 1c849acdd57859256d94080682ea933680c9cef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 3 Feb 2020 16:00:17 +0100 Subject: [PATCH 64/69] [Logs UI] Add smoke tests for log rate and categories tabs (#55088) This adds function smoke tests for the new log rate and categories tabs in the Logs UI. --- x-pack/test/functional/apps/infra/index.ts | 2 + .../apps/infra/log_entry_categories_tab.ts | 28 +++++++++ .../apps/infra/log_entry_rate_tab.ts | 28 +++++++++ .../apps/infra/logs_source_configuration.ts | 62 ++++++++++++------- .../page_objects/infra_logs_page.ts | 10 +-- x-pack/test/functional/services/index.ts | 4 +- .../test/functional/services/logs_ui/index.ts | 18 ++++++ .../services/logs_ui/log_entry_categories.ts | 23 +++++++ .../services/logs_ui/log_entry_rate.ts | 23 +++++++ .../log_stream.ts} | 17 +++-- 10 files changed, 182 insertions(+), 33 deletions(-) create mode 100644 x-pack/test/functional/apps/infra/log_entry_categories_tab.ts create mode 100644 x-pack/test/functional/apps/infra/log_entry_rate_tab.ts create mode 100644 x-pack/test/functional/services/logs_ui/index.ts create mode 100644 x-pack/test/functional/services/logs_ui/log_entry_categories.ts create mode 100644 x-pack/test/functional/services/logs_ui/log_entry_rate.ts rename x-pack/test/functional/services/{infra_log_stream.ts => logs_ui/log_stream.ts} (70%) diff --git a/x-pack/test/functional/apps/infra/index.ts b/x-pack/test/functional/apps/infra/index.ts index b706dc8cce5469..597b522a88c51b 100644 --- a/x-pack/test/functional/apps/infra/index.ts +++ b/x-pack/test/functional/apps/infra/index.ts @@ -12,6 +12,8 @@ export default ({ loadTestFile }: FtrProviderContext) => { loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./feature_controls')); + loadTestFile(require.resolve('./log_entry_categories_tab')); + loadTestFile(require.resolve('./log_entry_rate_tab')); loadTestFile(require.resolve('./logs_source_configuration')); loadTestFile(require.resolve('./metrics_source_configuration')); loadTestFile(require.resolve('./link_to')); diff --git a/x-pack/test/functional/apps/infra/log_entry_categories_tab.ts b/x-pack/test/functional/apps/infra/log_entry_categories_tab.ts new file mode 100644 index 00000000000000..c703738e37228a --- /dev/null +++ b/x-pack/test/functional/apps/infra/log_entry_categories_tab.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const logsUi = getService('logsUi'); + const retry = getService('retry'); + + describe('Log Entry Categories Tab', function() { + this.tags('smoke'); + + describe('with a trial license', () => { + it('is visible', async () => { + await logsUi.logEntryCategoriesPage.navigateTo(); + + await retry.try(async () => { + expect(await logsUi.logEntryCategoriesPage.getSetupScreen()).to.be.ok(); + }); + }); + }); + }); +}; diff --git a/x-pack/test/functional/apps/infra/log_entry_rate_tab.ts b/x-pack/test/functional/apps/infra/log_entry_rate_tab.ts new file mode 100644 index 00000000000000..95228a520aaa25 --- /dev/null +++ b/x-pack/test/functional/apps/infra/log_entry_rate_tab.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const logsUi = getService('logsUi'); + const retry = getService('retry'); + + describe('Log Entry Rate Tab', function() { + this.tags('smoke'); + + describe('with a trial license', () => { + it('is visible', async () => { + await logsUi.logEntryRatePage.navigateTo(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getSetupScreen()).to.be.ok(); + }); + }); + }); + }); +}; diff --git a/x-pack/test/functional/apps/infra/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs_source_configuration.ts index 183acf3a980eeb..ecad5a40ec42e9 100644 --- a/x-pack/test/functional/apps/infra/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs_source_configuration.ts @@ -10,12 +10,14 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); - const infraLogStream = getService('infraLogStream'); + const logsUi = getService('logsUi'); const infraSourceConfigurationForm = getService('infraSourceConfigurationForm'); const pageObjects = getPageObjects(['common', 'infraLogs']); + const retry = getService('retry'); describe('Logs Source Configuration', function() { this.tags('smoke'); + before(async () => { await esArchiver.load('empty_kibana'); }); @@ -32,8 +34,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('can change the log indices to a pattern that matches nothing', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); - await infraSourceConfigurationForm.getForm(); + await pageObjects.infraLogs.navigateToTab('settings'); + + await retry.try(async () => { + await infraSourceConfigurationForm.getForm(); + }); const nameInput = await infraSourceConfigurationForm.getNameInput(); await nameInput.clearValueWithKeyboard({ charByChar: true }); @@ -47,13 +52,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('renders the no indices screen when no indices match the pattern', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); - await pageObjects.infraLogs.getNoLogsIndicesPrompt(); + await logsUi.logStreamPage.navigateTo(); + + await retry.try(async () => { + await logsUi.logStreamPage.getNoLogsIndicesPrompt(); + }); }); it('can change the log indices back to a pattern that matches something', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); - await infraSourceConfigurationForm.getForm(); + await pageObjects.infraLogs.navigateToTab('settings'); + + await retry.try(async () => { + await infraSourceConfigurationForm.getForm(); + }); const logIndicesInput = await infraSourceConfigurationForm.getLogIndicesInput(); await logIndicesInput.clearValueWithKeyboard({ charByChar: true }); @@ -63,16 +74,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('renders the default log columns with their headers', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); - const columnHeaderLabels = await infraLogStream.getColumnHeaderLabels(); + await logsUi.logStreamPage.navigateTo(); - expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'event.dataset', 'Message']); + await retry.try(async () => { + const columnHeaderLabels = await logsUi.logStreamPage.getColumnHeaderLabels(); - const logStreamEntries = await infraLogStream.getStreamEntries(); + expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'event.dataset', 'Message']); + }); + + const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); expect(logStreamEntries.length).to.be.greaterThan(0); const firstLogStreamEntry = logStreamEntries[0]; - const logStreamEntryColumns = await infraLogStream.getLogColumnsOfStreamEntry( + const logStreamEntryColumns = await logsUi.logStreamPage.getLogColumnsOfStreamEntry( firstLogStreamEntry ); @@ -80,32 +94,34 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('can change the log columns', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); - await infraSourceConfigurationForm.getForm(); + await pageObjects.infraLogs.navigateToTab('settings'); + + await retry.try(async () => { + await infraSourceConfigurationForm.getForm(); + }); await infraSourceConfigurationForm.removeAllLogColumns(); await infraSourceConfigurationForm.addTimestampLogColumn(); await infraSourceConfigurationForm.addFieldLogColumn('host.name'); - // await infraSourceConfigurationForm.moveLogColumn(0, 1); - await infraSourceConfigurationForm.saveConfiguration(); }); it('renders the changed log columns with their headers', async () => { - await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); - const columnHeaderLabels = await infraLogStream.getColumnHeaderLabels(); + await logsUi.logStreamPage.navigateTo(); + + await retry.try(async () => { + const columnHeaderLabels = await logsUi.logStreamPage.getColumnHeaderLabels(); - // TODO: make test more robust - // expect(columnHeaderLabels).to.eql(['host.name', 'Timestamp']); - expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'host.name']); + expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'host.name']); + }); - const logStreamEntries = await infraLogStream.getStreamEntries(); + const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); expect(logStreamEntries.length).to.be.greaterThan(0); const firstLogStreamEntry = logStreamEntries[0]; - const logStreamEntryColumns = await infraLogStream.getLogColumnsOfStreamEntry( + const logStreamEntryColumns = await logsUi.logStreamPage.getLogColumnsOfStreamEntry( firstLogStreamEntry ); diff --git a/x-pack/test/functional/page_objects/infra_logs_page.ts b/x-pack/test/functional/page_objects/infra_logs_page.ts index 6eb1349210bae3..1c58f8dc41eba0 100644 --- a/x-pack/test/functional/page_objects/infra_logs_page.ts +++ b/x-pack/test/functional/page_objects/infra_logs_page.ts @@ -18,12 +18,14 @@ export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProvide await pageObjects.common.navigateToApp('infraLogs'); }, - async getLogStream() { - return await testSubjects.find('logStream'); + async navigateToTab(logsUiTab: LogsUiTab) { + await pageObjects.common.navigateToActualUrl('infraLogs', `/logs/${logsUiTab}`); }, - async getNoLogsIndicesPrompt() { - return await testSubjects.find('noLogsIndicesPrompt'); + async getLogStream() { + return await testSubjects.find('logStream'); }, }; } + +type LogsUiTab = 'log-categories' | 'log-rate' | 'settings' | 'stream'; diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index 84d5a792ae6cae..aec91ba9e90341 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -46,7 +46,7 @@ import { GrokDebuggerProvider } from './grok_debugger'; import { UserMenuProvider } from './user_menu'; import { UptimeProvider } from './uptime'; import { InfraSourceConfigurationFormProvider } from './infra_source_configuration_form'; -import { InfraLogStreamProvider } from './infra_log_stream'; +import { LogsUiProvider } from './logs_ui'; import { MachineLearningProvider } from './ml'; import { TransformProvider } from './transform'; @@ -88,7 +88,7 @@ export const services = { userMenu: UserMenuProvider, uptime: UptimeProvider, infraSourceConfigurationForm: InfraSourceConfigurationFormProvider, - infraLogStream: InfraLogStreamProvider, + logsUi: LogsUiProvider, ml: MachineLearningProvider, transform: TransformProvider, }; diff --git a/x-pack/test/functional/services/logs_ui/index.ts b/x-pack/test/functional/services/logs_ui/index.ts new file mode 100644 index 00000000000000..c70a8470aafce3 --- /dev/null +++ b/x-pack/test/functional/services/logs_ui/index.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { LogEntryCategoriesPageProvider } from './log_entry_categories'; +import { LogEntryRatePageProvider } from './log_entry_rate'; +import { LogStreamPageProvider } from './log_stream'; + +export function LogsUiProvider(context: FtrProviderContext) { + return { + logEntryCategoriesPage: LogEntryCategoriesPageProvider(context), + logEntryRatePage: LogEntryRatePageProvider(context), + logStreamPage: LogStreamPageProvider(context), + }; +} diff --git a/x-pack/test/functional/services/logs_ui/log_entry_categories.ts b/x-pack/test/functional/services/logs_ui/log_entry_categories.ts new file mode 100644 index 00000000000000..b9a400b1556797 --- /dev/null +++ b/x-pack/test/functional/services/logs_ui/log_entry_categories.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function LogEntryCategoriesPageProvider({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['infraLogs']); + const testSubjects = getService('testSubjects'); + + return { + async navigateTo() { + pageObjects.infraLogs.navigateToTab('log-categories'); + }, + + async getSetupScreen(): Promise { + return await testSubjects.find('logEntryCategoriesSetupPage'); + }, + }; +} diff --git a/x-pack/test/functional/services/logs_ui/log_entry_rate.ts b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts new file mode 100644 index 00000000000000..96c69e85aa0a48 --- /dev/null +++ b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function LogEntryRatePageProvider({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['infraLogs']); + const testSubjects = getService('testSubjects'); + + return { + async navigateTo() { + pageObjects.infraLogs.navigateToTab('log-rate'); + }, + + async getSetupScreen(): Promise { + return await testSubjects.find('logEntryRateSetupPage'); + }, + }; +} diff --git a/x-pack/test/functional/services/infra_log_stream.ts b/x-pack/test/functional/services/logs_ui/log_stream.ts similarity index 70% rename from x-pack/test/functional/services/infra_log_stream.ts rename to x-pack/test/functional/services/logs_ui/log_stream.ts index af113d3afffb42..ce37d2d5a60daa 100644 --- a/x-pack/test/functional/services/infra_log_stream.ts +++ b/x-pack/test/functional/services/logs_ui/log_stream.ts @@ -4,14 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { FtrProviderContext } from '../ftr_provider_context'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; -export function InfraLogStreamProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); +export function LogStreamPageProvider({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['infraLogs']); const retry = getService('retry'); + const testSubjects = getService('testSubjects'); return { + async navigateTo() { + pageObjects.infraLogs.navigateToTab('stream'); + }, + async getColumnHeaderLabels(): Promise { const columnHeaderElements: WebElementWrapper[] = await testSubjects.findAll( '~logColumnHeader' @@ -35,5 +40,9 @@ export function InfraLogStreamProvider({ getService }: FtrProviderContext) { ): Promise { return await testSubjects.findAllDescendant('~logColumn', entryElement); }, + + async getNoLogsIndicesPrompt() { + return await testSubjects.find('noLogsIndicesPrompt'); + }, }; } From 85988386b6fcc5f71c0b01fd3b6fd14767bdb93d Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Mon, 3 Feb 2020 07:04:23 -0800 Subject: [PATCH 65/69] Containers (#56571) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 💡 move state containers to /common folder * refactor: 💡 remove RecursiveReadonly type in state containers * fix: 🐛 assume we are in production by default on server-side Co-authored-by: Elastic Machine --- src/plugins/kibana_utils/common/index.ts | 1 + .../create_state_container.test.ts | 0 .../create_state_container.ts | 25 +++++++++++-------- ...ate_state_container_react_helpers.test.tsx | 0 .../create_state_container_react_helpers.ts | 0 .../state_containers/index.ts | 0 .../state_containers/types.ts | 18 ++++++------- .../demos/state_containers/counter.ts | 2 +- .../demos/state_containers/todomvc.ts | 2 +- .../kibana_utils/demos/state_sync/url.ts | 2 +- src/plugins/kibana_utils/public/index.ts | 2 +- .../public/state_sync/state_sync.test.ts | 2 +- .../public/state_sync/state_sync.ts | 2 +- .../kibana_utils/public/state_sync/types.ts | 2 +- 14 files changed, 31 insertions(+), 27 deletions(-) rename src/plugins/kibana_utils/{public => common}/state_containers/create_state_container.test.ts (100%) rename src/plugins/kibana_utils/{public => common}/state_containers/create_state_container.ts (86%) rename src/plugins/kibana_utils/{public => common}/state_containers/create_state_container_react_helpers.test.tsx (100%) rename src/plugins/kibana_utils/{public => common}/state_containers/create_state_container_react_helpers.ts (100%) rename src/plugins/kibana_utils/{public => common}/state_containers/index.ts (100%) rename src/plugins/kibana_utils/{public => common}/state_containers/types.ts (88%) diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index bfb45b88964d89..d4aeb2c0fe4ad4 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -19,4 +19,5 @@ export * from './defer'; export * from './of'; +export * from './state_containers'; export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value'; diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container.test.ts b/src/plugins/kibana_utils/common/state_containers/create_state_container.test.ts similarity index 100% rename from src/plugins/kibana_utils/public/state_containers/create_state_container.test.ts rename to src/plugins/kibana_utils/common/state_containers/create_state_container.test.ts diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container.ts b/src/plugins/kibana_utils/common/state_containers/create_state_container.ts similarity index 86% rename from src/plugins/kibana_utils/public/state_containers/create_state_container.ts rename to src/plugins/kibana_utils/common/state_containers/create_state_container.ts index d420aec30f068c..78bfc0c3e90906 100644 --- a/src/plugins/kibana_utils/public/state_containers/create_state_container.ts +++ b/src/plugins/kibana_utils/common/state_containers/create_state_container.ts @@ -19,7 +19,6 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; -import { RecursiveReadonly } from '@kbn/utility-types'; import deepFreeze from 'deep-freeze-strict'; import { PureTransitionsToTransitions, @@ -32,14 +31,18 @@ import { const $$observable = (typeof Symbol === 'function' && (Symbol as any).observable) || '@@observable'; const $$setActionType = '@@SET'; -const freeze: (value: T) => RecursiveReadonly = - process.env.NODE_ENV !== 'production' - ? (value: T): RecursiveReadonly => { - const isFreezable = value !== null && typeof value === 'object'; - if (isFreezable) return deepFreeze(value) as RecursiveReadonly; - return value as RecursiveReadonly; - } - : (value: T) => value as RecursiveReadonly; +const isProduction = + typeof window === 'object' + ? process.env.NODE_ENV === 'production' + : !process.env.NODE_ENV || process.env.NODE_ENV === 'production'; + +const freeze: (value: T) => T = isProduction + ? (value: T) => value as T + : (value: T): T => { + const isFreezable = value !== null && typeof value === 'object'; + if (isFreezable) return deepFreeze(value) as T; + return value as T; + }; export function createStateContainer( defaultState: State @@ -66,7 +69,7 @@ export function createStateContainer< pureTransitions: PureTransitions = {} as PureTransitions, pureSelectors: PureSelectors = {} as PureSelectors ): ReduxLikeStateContainer { - const data$ = new BehaviorSubject>(freeze(defaultState)); + const data$ = new BehaviorSubject(freeze(defaultState)); const state$ = data$.pipe(skip(1)); const get = () => data$.getValue(); const container: ReduxLikeStateContainer = { @@ -101,7 +104,7 @@ export function createStateContainer< ), addMiddleware: middleware => (container.dispatch = middleware(container as any)(container.dispatch)), - subscribe: (listener: (state: RecursiveReadonly) => void) => { + subscribe: (listener: (state: State) => void) => { const subscription = state$.subscribe(listener); return () => subscription.unsubscribe(); }, diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.test.tsx b/src/plugins/kibana_utils/common/state_containers/create_state_container_react_helpers.test.tsx similarity index 100% rename from src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.test.tsx rename to src/plugins/kibana_utils/common/state_containers/create_state_container_react_helpers.test.tsx diff --git a/src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.ts b/src/plugins/kibana_utils/common/state_containers/create_state_container_react_helpers.ts similarity index 100% rename from src/plugins/kibana_utils/public/state_containers/create_state_container_react_helpers.ts rename to src/plugins/kibana_utils/common/state_containers/create_state_container_react_helpers.ts diff --git a/src/plugins/kibana_utils/public/state_containers/index.ts b/src/plugins/kibana_utils/common/state_containers/index.ts similarity index 100% rename from src/plugins/kibana_utils/public/state_containers/index.ts rename to src/plugins/kibana_utils/common/state_containers/index.ts diff --git a/src/plugins/kibana_utils/public/state_containers/types.ts b/src/plugins/kibana_utils/common/state_containers/types.ts similarity index 88% rename from src/plugins/kibana_utils/public/state_containers/types.ts rename to src/plugins/kibana_utils/common/state_containers/types.ts index 5f27a3d2c1dcad..26a29bc470e8ac 100644 --- a/src/plugins/kibana_utils/public/state_containers/types.ts +++ b/src/plugins/kibana_utils/common/state_containers/types.ts @@ -18,7 +18,7 @@ */ import { Observable } from 'rxjs'; -import { Ensure, RecursiveReadonly } from '@kbn/utility-types'; +import { Ensure } from '@kbn/utility-types'; export type BaseState = object; export interface TransitionDescription { @@ -27,7 +27,7 @@ export interface TransitionDescription = (...args: Args) => State; export type PureTransition = ( - state: RecursiveReadonly + state: State ) => Transition; export type EnsurePureTransition = Ensure>; export type PureTransitionToTransition> = ReturnType; @@ -36,9 +36,9 @@ export type PureTransitionsToTransitions = { }; export interface BaseStateContainer { - get: () => RecursiveReadonly; + get: () => State; set: (state: State) => void; - state$: Observable>; + state$: Observable; } export interface StateContainer< @@ -55,12 +55,12 @@ export interface ReduxLikeStateContainer< PureTransitions extends object = {}, PureSelectors extends object = {} > extends StateContainer { - getState: () => RecursiveReadonly; - reducer: Reducer>; - replaceReducer: (nextReducer: Reducer>) => void; + getState: () => State; + reducer: Reducer; + replaceReducer: (nextReducer: Reducer) => void; dispatch: (action: TransitionDescription) => void; - addMiddleware: (middleware: Middleware>) => void; - subscribe: (listener: (state: RecursiveReadonly) => void) => () => void; + addMiddleware: (middleware: Middleware) => void; + subscribe: (listener: (state: State) => void) => () => void; } export type Dispatch = (action: T) => void; diff --git a/src/plugins/kibana_utils/demos/state_containers/counter.ts b/src/plugins/kibana_utils/demos/state_containers/counter.ts index 4ddf532c1506db..0484a906a60d3b 100644 --- a/src/plugins/kibana_utils/demos/state_containers/counter.ts +++ b/src/plugins/kibana_utils/demos/state_containers/counter.ts @@ -17,7 +17,7 @@ * under the License. */ -import { createStateContainer } from '../../public/state_containers'; +import { createStateContainer } from '../../common/state_containers'; interface State { count: number; diff --git a/src/plugins/kibana_utils/demos/state_containers/todomvc.ts b/src/plugins/kibana_utils/demos/state_containers/todomvc.ts index e807783a56f319..0a07d721479b3b 100644 --- a/src/plugins/kibana_utils/demos/state_containers/todomvc.ts +++ b/src/plugins/kibana_utils/demos/state_containers/todomvc.ts @@ -17,7 +17,7 @@ * under the License. */ -import { createStateContainer, PureTransition } from '../../public/state_containers'; +import { createStateContainer, PureTransition } from '../../common/state_containers'; export interface TodoItem { text: string; diff --git a/src/plugins/kibana_utils/demos/state_sync/url.ts b/src/plugins/kibana_utils/demos/state_sync/url.ts index 2c426cae6733a4..80c016950d2242 100644 --- a/src/plugins/kibana_utils/demos/state_sync/url.ts +++ b/src/plugins/kibana_utils/demos/state_sync/url.ts @@ -18,7 +18,7 @@ */ import { defaultState, pureTransitions, TodoActions, TodoState } from '../state_containers/todomvc'; -import { BaseState, BaseStateContainer, createStateContainer } from '../../public/state_containers'; +import { BaseState, BaseStateContainer, createStateContainer } from '../../common/state_containers'; import { createKbnUrlStateStorage, syncState, diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 00c1c95028b4dc..78828ad9c4b2de 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -25,7 +25,7 @@ export * from './field_wildcard'; export * from './parse'; export * from './render_complete'; export * from './resize_checker'; -export * from './state_containers'; +export * from '../common/state_containers'; export * from './storage'; export { hashedItemStore, HashedItemStore } from './storage/hashed_item_store'; export { diff --git a/src/plugins/kibana_utils/public/state_sync/state_sync.test.ts b/src/plugins/kibana_utils/public/state_sync/state_sync.test.ts index 17f41483a0a21e..c55c60f9b0f890 100644 --- a/src/plugins/kibana_utils/public/state_sync/state_sync.test.ts +++ b/src/plugins/kibana_utils/public/state_sync/state_sync.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { BaseState, BaseStateContainer, createStateContainer } from '../state_containers'; +import { BaseState, BaseStateContainer, createStateContainer } from '../../common/state_containers'; import { defaultState, pureTransitions, diff --git a/src/plugins/kibana_utils/public/state_sync/state_sync.ts b/src/plugins/kibana_utils/public/state_sync/state_sync.ts index 28d133829e07c4..ed57723f8f2b7b 100644 --- a/src/plugins/kibana_utils/public/state_sync/state_sync.ts +++ b/src/plugins/kibana_utils/public/state_sync/state_sync.ts @@ -23,7 +23,7 @@ import defaultComparator from 'fast-deep-equal'; import { IStateSyncConfig } from './types'; import { IStateStorage } from './state_sync_state_storage'; import { distinctUntilChangedWithInitialValue } from '../../common'; -import { BaseState } from '../state_containers'; +import { BaseState } from '../../common/state_containers'; import { applyDiff } from '../state_management/utils/diff_object'; /** diff --git a/src/plugins/kibana_utils/public/state_sync/types.ts b/src/plugins/kibana_utils/public/state_sync/types.ts index 3009c1d161a532..2acb466d92e920 100644 --- a/src/plugins/kibana_utils/public/state_sync/types.ts +++ b/src/plugins/kibana_utils/public/state_sync/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { BaseState, BaseStateContainer } from '../state_containers/types'; +import { BaseState, BaseStateContainer } from '../../common/state_containers/types'; import { IStateStorage } from './state_sync_state_storage'; export interface INullableBaseStateContainer From c86ee1b6ea001863fde399721febaf1704fd2fc0 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Mon, 3 Feb 2020 07:05:39 -0800 Subject: [PATCH 66/69] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20AppArch=20p?= =?UTF-8?q?lugins=20to=20CODEOWNERS=20(#56397)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: 🤖 add AppArch plugins to CODEOWNERS And sort the list alphabetically. * chore: 🤖 add @kbn/interpreter to AppArch CODEOWNERS Co-authored-by: Elastic Machine --- .github/CODEOWNERS | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2e2b20a46baede..0b0addf117f6fc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,15 +28,7 @@ /src/plugins/dev_tools/ @elastic/kibana-app # App Architecture -/src/plugins/data/ @elastic/kibana-app-arch -/src/plugins/embeddable/ @elastic/kibana-app-arch -/src/plugins/expressions/ @elastic/kibana-app-arch -/src/plugins/kibana_react/ @elastic/kibana-app-arch -/src/plugins/kibana_utils/ @elastic/kibana-app-arch -/src/plugins/navigation/ @elastic/kibana-app-arch -/src/plugins/ui_actions/ @elastic/kibana-app-arch -/src/plugins/visualizations/ @elastic/kibana-app-arch -/x-pack/plugins/advanced_ui_actions/ @elastic/kibana-app-arch +/packages/kbn-interpreter/ @elastic/kibana-app-arch /src/legacy/core_plugins/data/ @elastic/kibana-app-arch /src/legacy/core_plugins/elasticsearch/lib/create_proxy.js @elastic/kibana-app-arch /src/legacy/core_plugins/embeddable_api/ @elastic/kibana-app-arch @@ -48,6 +40,19 @@ /src/legacy/core_plugins/kibana/server/routes/api/suggestions/ @elastic/kibana-app-arch /src/legacy/core_plugins/visualizations/ @elastic/kibana-app-arch /src/legacy/server/index_patterns/ @elastic/kibana-app-arch +/src/plugins/bfetch/ @elastic/kibana-app-arch +/src/plugins/dashboard_embeddable_container/ @elastic/kibana-app-arch +/src/plugins/data/ @elastic/kibana-app-arch +/src/plugins/embeddable/ @elastic/kibana-app-arch +/src/plugins/expressions/ @elastic/kibana-app-arch +/src/plugins/inspector/ @elastic/kibana-app-arch +/src/plugins/kibana_react/ @elastic/kibana-app-arch +/src/plugins/kibana_utils/ @elastic/kibana-app-arch +/src/plugins/management/ @elastic/kibana-app-arch +/src/plugins/navigation/ @elastic/kibana-app-arch +/src/plugins/ui_actions/ @elastic/kibana-app-arch +/src/plugins/visualizations/ @elastic/kibana-app-arch +/x-pack/plugins/advanced_ui_actions/ @elastic/kibana-app-arch # APM /x-pack/legacy/plugins/apm/ @elastic/apm-ui From 95e40e7fa3a7be1b9818c67177f3e8f4927eb9ba Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 3 Feb 2020 16:22:38 +0100 Subject: [PATCH 67/69] [Uptime] Refresh absolute date ranges for Ping Histogram (#56381) * fix abs date mismatch * fixed types * update pr * simplify params Co-authored-by: Elastic Machine --- .../connected/charts/ping_histogram.tsx | 36 +- .../connected/charts/snapshot_container.tsx | 95 +++ .../filter_group/filter_group_container.tsx | 17 +- .../public/components/connected/index.ts | 3 + .../monitor/status_bar_container.tsx | 85 +++ .../monitor/status_details_container.tsx | 64 ++ .../monitor_charts.test.tsx.snap | 2 - .../__tests__/monitor_charts.test.tsx | 2 - .../functional/__tests__/snapshot.test.tsx | 4 +- .../monitor_bar_series.test.tsx.snap | 156 +++-- .../__tests__/monitor_bar_series.test.tsx | 159 ++++- .../functional/charts/monitor_bar_series.tsx | 25 +- .../public/components/functional/index.ts | 2 - .../components/functional/monitor_charts.tsx | 26 +- .../__snapshots__/monitor_list.test.tsx.snap | 554 ++++++++++++++++++ .../monitor_list_pagination.test.tsx.snap | 4 +- .../__tests__/monitor_list.test.tsx | 25 +- .../monitor_list_pagination.test.tsx | 6 +- .../functional/monitor_list/monitor_list.tsx | 20 +- .../monitor_status.bar.test.tsx.snap | 0 .../__test__}/monitor_status.bar.test.tsx | 12 +- .../monitor_status_details/index.ts | 31 +- .../monitor_status_bar/index.ts | 44 +- .../monitor_status_bar/monitor_status_bar.tsx | 26 +- .../monitor_status_details.tsx | 27 +- .../public/components/functional/snapshot.tsx | 107 +--- .../components/functional/status_panel.tsx | 42 +- .../public/hooks/update_kuery_string.ts | 4 +- .../plugins/uptime/public/pages/monitor.tsx | 17 +- .../plugins/uptime/public/pages/overview.tsx | 11 +- 30 files changed, 1148 insertions(+), 458 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx rename x-pack/legacy/plugins/uptime/public/components/functional/{__tests__ => monitor_status_details/__test__}/__snapshots__/monitor_status.bar.test.tsx.snap (100%) rename x-pack/legacy/plugins/uptime/public/components/functional/{__tests__ => monitor_status_details/__test__}/monitor_status.bar.test.tsx (79%) diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx index a6607ca81fc183..cbdd921a36e81b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/ping_histogram.tsx @@ -15,34 +15,40 @@ import { getPingHistogram } from '../../../state/actions'; import { selectPingHistogram } from '../../../state/selectors'; import { withResponsiveWrapper, ResponsiveWrapperProps } from '../../higher_order'; import { GetPingHistogramParams, HistogramResult } from '../../../../common/types'; +import { useUrlParams } from '../../../hooks'; -type Props = GetPingHistogramParams & - ResponsiveWrapperProps & - PingHistogramComponentProps & - DispatchProps & { lastRefresh: number }; +type Props = ResponsiveWrapperProps & + Pick & + DispatchProps & { lastRefresh: number; monitorId?: string }; const PingHistogramContainer: React.FC = ({ data, loadData, - statusFilter, - filters, - dateStart, - dateEnd, - absoluteStartDate, - absoluteEndDate, monitorId, lastRefresh, - ...props + height, + loading, }) => { + const [getUrlParams] = useUrlParams(); + const { + absoluteDateRangeStart, + absoluteDateRangeEnd, + dateRangeStart: dateStart, + dateRangeEnd: dateEnd, + statusFilter, + filters, + } = getUrlParams(); + useEffect(() => { loadData({ monitorId, dateStart, dateEnd, statusFilter, filters }); }, [loadData, dateStart, dateEnd, monitorId, filters, statusFilter, lastRefresh]); return ( ); }; @@ -68,7 +74,7 @@ const mapDispatchToProps = (dispatch: any): DispatchProps => ({ export const PingHistogram = connect< StateProps, DispatchProps, - PingHistogramComponentProps, + Pick, AppState >( mapStateToProps, diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx new file mode 100644 index 00000000000000..6d01ebae1e100f --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { useUrlParams } from '../../../hooks'; +import { AppState } from '../../../state'; +import { fetchSnapshotCount } from '../../../state/actions'; +import { SnapshotComponent } from '../../functional/snapshot'; +import { Snapshot as SnapshotType } from '../../../../common/runtime_types'; + +/** + * Props expected from parent components. + */ +interface OwnProps { + /** + * Height is needed, since by default charts takes height of 100% + */ + height?: string; +} + +/** + * Props given by the Redux store based on action input. + */ +interface StoreProps { + count: SnapshotType; + lastRefresh: number; + loading: boolean; +} + +/** + * Contains functions that will dispatch actions used + * for this component's life cycle + */ +interface DispatchProps { + loadSnapshotCount: typeof fetchSnapshotCount; +} + +/** + * Props used to render the Snapshot component. + */ +type Props = OwnProps & StoreProps & DispatchProps; + +export const Container: React.FC = ({ + count, + height, + lastRefresh, + loading, + loadSnapshotCount, +}: Props) => { + const [getUrlParams] = useUrlParams(); + const { dateRangeStart, dateRangeEnd, statusFilter, filters } = getUrlParams(); + + useEffect(() => { + loadSnapshotCount(dateRangeStart, dateRangeEnd, filters, statusFilter); + }, [dateRangeStart, dateRangeEnd, filters, lastRefresh, loadSnapshotCount, statusFilter]); + return ; +}; + +/** + * Provides state to connected component. + * @param state the root app state + */ +const mapStateToProps = ({ + snapshot: { count, loading }, + ui: { lastRefresh }, +}: AppState): StoreProps => ({ + count, + lastRefresh, + loading, +}); + +/** + * Used for fetching snapshot counts. + * @param dispatch redux-provided action dispatcher + */ +const mapDispatchToProps = (dispatch: any) => ({ + loadSnapshotCount: ( + dateRangeStart: string, + dateRangeEnd: string, + filters?: string, + statusFilter?: string + ): DispatchProps => { + return dispatch(fetchSnapshotCount(dateRangeStart, dateRangeEnd, filters, statusFilter)); + }, +}); + +export const Snapshot = connect( + // @ts-ignore connect is expecting null | undefined for some reason + mapStateToProps, + mapDispatchToProps +)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx index 2d1c21d1c997da..569c6bb883cbdc 100644 --- a/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/connected/filter_group/filter_group_container.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect } from 'react'; +import React, { useContext, useEffect } from 'react'; import { connect } from 'react-redux'; import { useUrlParams } from '../../../hooks'; import { parseFiltersMap } from '../../functional/filter_group/parse_filter_map'; @@ -12,6 +12,7 @@ import { AppState } from '../../../state'; import { fetchOverviewFilters, GetOverviewFiltersPayload } from '../../../state/actions'; import { FilterGroupComponent } from '../../functional/filter_group'; import { OverviewFilters } from '../../../../common/runtime_types/overview_filters'; +import { UptimeRefreshContext } from '../../../contexts'; interface OwnProps { esFilters?: string; @@ -37,8 +38,9 @@ export const Container: React.FC = ({ loadFilterGroup, overviewFilters, }: Props) => { - const [getUrlParams, updateUrl] = useUrlParams(); + const { lastRefresh } = useContext(UptimeRefreshContext); + const [getUrlParams, updateUrl] = useUrlParams(); const { dateRangeStart, dateRangeEnd, statusFilter, filters: urlFilters } = getUrlParams(); useEffect(() => { @@ -53,7 +55,16 @@ export const Container: React.FC = ({ statusFilter, tags: filterSelections.tags ?? [], }); - }, [dateRangeStart, dateRangeEnd, esKuery, esFilters, statusFilter, urlFilters, loadFilterGroup]); + }, [ + lastRefresh, + dateRangeStart, + dateRangeEnd, + esKuery, + esFilters, + statusFilter, + urlFilters, + loadFilterGroup, + ]); // update filters in the URL from filter group const onFilterUpdate = (filtersKuery: string) => { diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/index.ts b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts index 5bb0d1ae8468f9..2fd4c762cf45f5 100644 --- a/x-pack/legacy/plugins/uptime/public/components/connected/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts @@ -5,6 +5,9 @@ */ export { PingHistogram } from './charts/ping_histogram'; +export { Snapshot } from './charts/snapshot_container'; export { KueryBar } from './kuerybar/kuery_bar_container'; export { OverviewPage } from './pages/overview_container'; export { FilterGroup } from './filter_group/filter_group_container'; +export { MonitorStatusDetails } from './monitor/status_details_container'; +export { MonitorStatusBar } from './monitor/status_bar_container'; diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx new file mode 100644 index 00000000000000..db6337732091a9 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { AppState } from '../../../state'; +import { selectMonitorLocations, selectMonitorStatus } from '../../../state/selectors'; +import { MonitorStatusBarComponent } from '../../functional/monitor_status_details/monitor_status_bar'; +import { getMonitorStatus, getSelectedMonitor } from '../../../state/actions'; +import { useUrlParams } from '../../../hooks'; +import { Ping } from '../../../../common/graphql/types'; +import { MonitorLocations } from '../../../../common/runtime_types/monitor'; +import { UptimeRefreshContext } from '../../../contexts'; + +interface StateProps { + monitorStatus: Ping; + monitorLocations: MonitorLocations; +} + +interface DispatchProps { + loadMonitorStatus: (dateStart: string, dateEnd: string, monitorId: string) => void; +} + +interface OwnProps { + monitorId: string; +} + +type Props = OwnProps & StateProps & DispatchProps; + +export const Container: React.FC = ({ + loadMonitorStatus, + monitorId, + monitorStatus, + monitorLocations, +}: Props) => { + const { lastRefresh } = useContext(UptimeRefreshContext); + + const [getUrlParams] = useUrlParams(); + const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams(); + + useEffect(() => { + loadMonitorStatus(dateStart, dateEnd, monitorId); + }, [monitorId, dateStart, dateEnd, loadMonitorStatus, lastRefresh]); + + return ( + + ); +}; + +const mapStateToProps = (state: AppState, ownProps: OwnProps) => ({ + monitorStatus: selectMonitorStatus(state), + monitorLocations: selectMonitorLocations(state, ownProps.monitorId), +}); + +const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ + loadMonitorStatus: (dateStart: string, dateEnd: string, monitorId: string) => { + dispatch( + getMonitorStatus({ + monitorId, + dateStart, + dateEnd, + }) + ); + dispatch( + getSelectedMonitor({ + monitorId, + }) + ); + }, +}); + +// @ts-ignore TODO: Investigate typescript issues here +export const MonitorStatusBar = connect( + // @ts-ignore TODO: Investigate typescript issues here + mapStateToProps, + mapDispatchToProps +)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx new file mode 100644 index 00000000000000..6929e3bd64c4d0 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { useUrlParams } from '../../../hooks'; +import { AppState } from '../../../state'; +import { selectMonitorLocations } from '../../../state/selectors'; +import { fetchMonitorLocations, MonitorLocationsPayload } from '../../../state/actions/monitor'; +import { MonitorStatusDetailsComponent } from '../../functional/monitor_status_details'; +import { MonitorLocations } from '../../../../common/runtime_types'; +import { UptimeRefreshContext } from '../../../contexts'; + +interface OwnProps { + monitorId: string; +} + +interface StoreProps { + monitorLocations: MonitorLocations; +} + +interface DispatchProps { + loadMonitorLocations: typeof fetchMonitorLocations; +} + +type Props = OwnProps & StoreProps & DispatchProps; + +export const Container: React.FC = ({ + loadMonitorLocations, + monitorLocations, + monitorId, +}: Props) => { + const { lastRefresh } = useContext(UptimeRefreshContext); + + const [getUrlParams] = useUrlParams(); + const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams(); + + useEffect(() => { + loadMonitorLocations({ dateStart, dateEnd, monitorId }); + }, [loadMonitorLocations, monitorId, dateStart, dateEnd, lastRefresh]); + + return ( + + ); +}; +const mapStateToProps = (state: AppState, { monitorId }: OwnProps) => ({ + monitorLocations: selectMonitorLocations(state, monitorId), +}); + +const mapDispatchToProps = (dispatch: Dispatch) => ({ + loadMonitorLocations: (params: MonitorLocationsPayload) => { + dispatch(fetchMonitorLocations(params)); + }, +}); + +export const MonitorStatusDetails = connect( + // @ts-ignore TODO: Investigate typescript issues here + mapStateToProps, + mapDispatchToProps +)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap index f6846dfb1164da..9853ed5cadfc9b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap @@ -180,8 +180,6 @@ exports[`MonitorCharts component renders the component without errors 1`] = ` }, } } - dateRangeEnd="2011-12-03T10:15:30+01:00" - dateRangeStart="2011-12-03T10:15:30+01:00" loading={false} mean="mean" monitorId="something" diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx index 81c60c8fbeaaa9..331b5c9c0b0965 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx @@ -73,8 +73,6 @@ describe('MonitorCharts component', () => { range="range" success="success" monitorId="something" - dateRangeStart="2011-12-03T10:15:30+01:00" - dateRangeEnd="2011-12-03T10:15:30+01:00" /> ) ); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot.test.tsx index d645eb21ac7766..214b0394369f7a 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { Snapshot } from '../../../../common/runtime_types'; -import { PresentationalComponent } from '../snapshot'; +import { SnapshotComponent } from '../snapshot'; describe('Snapshot component', () => { const snapshot: Snapshot = { @@ -17,7 +17,7 @@ describe('Snapshot component', () => { }; it('renders without errors', () => { - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap index c3b99c9785cbe0..8ca73879cab8c0 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap @@ -1,67 +1,107 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`MonitorBarSeries component renders a series when there are down items 1`] = ` +exports[`MonitorBarSeries component renders if the data series is present 1`] = `
    - - - - - +
    +
    +

    + No data to display +

    +
    +
    +
    `; + +exports[`MonitorBarSeries component shallow renders a series when there are down items 1`] = ` + + + +`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/monitor_bar_series.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/monitor_bar_series.test.tsx index 3cede0be00ef1c..c3e98134e438d8 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/monitor_bar_series.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/monitor_bar_series.test.tsx @@ -5,15 +5,16 @@ */ import React from 'react'; -import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { MonitorBarSeries, MonitorBarSeriesProps } from '../monitor_bar_series'; +import { renderWithRouter } from '../../../../lib'; +import { SummaryHistogramPoint } from '../../../../../common/graphql/types'; describe('MonitorBarSeries component', () => { let props: MonitorBarSeriesProps; + let histogramSeries: SummaryHistogramPoint[]; beforeEach(() => { props = { - absoluteStartDate: 1548697920000, - absoluteEndDate: 1548700920000, dangerColor: 'A danger color', histogramSeries: [ { @@ -33,20 +34,144 @@ describe('MonitorBarSeries component', () => { }, ], }; + histogramSeries = [ + { timestamp: 1580387868000, up: 0, down: 5 }, + { timestamp: 1580387904000, up: 0, down: 20 }, + { + timestamp: 1580387940000, + up: 0, + down: 19, + }, + { + timestamp: 1580387976000, + up: 0, + down: 16, + }, + { + timestamp: 1580388012000, + up: 0, + down: 20, + }, + { + timestamp: 1580388048000, + up: 0, + down: 15, + }, + { + timestamp: 1580388084000, + up: 0, + down: 20, + }, + { + timestamp: 1580388120000, + up: 0, + down: 19, + }, + { + timestamp: 1580388156000, + up: 0, + down: 16, + }, + { + timestamp: 1580388192000, + up: 0, + down: 20, + }, + { + timestamp: 1580388228000, + up: 0, + down: 15, + }, + { + timestamp: 1580388264000, + up: 0, + down: 20, + }, + { + timestamp: 1580388300000, + up: 0, + down: 19, + }, + { + timestamp: 1580388336000, + up: 0, + down: 16, + }, + { + timestamp: 1580388372000, + up: 0, + down: 20, + }, + { + timestamp: 1580388408000, + up: 0, + down: 15, + }, + { + timestamp: 1580388444000, + up: 0, + down: 20, + }, + { + timestamp: 1580388480000, + up: 0, + down: 19, + }, + { + timestamp: 1580388516000, + up: 0, + down: 16, + }, + { + timestamp: 1580388552000, + up: 0, + down: 20, + }, + { + timestamp: 1580388588000, + up: 0, + down: 15, + }, + { + timestamp: 1580388624000, + up: 0, + down: 20, + }, + { + timestamp: 1580388660000, + up: 0, + down: 19, + }, + { + timestamp: 1580388696000, + up: 0, + down: 16, + }, + { + timestamp: 1580388732000, + up: 0, + down: 20, + }, + { + timestamp: 1580388768000, + up: 0, + down: 10, + }, + ]; }); - it('renders a series when there are down items', () => { - const component = shallowWithIntl(); + it('shallow renders a series when there are down items', () => { + const component = shallowWithIntl(renderWithRouter()); expect(component).toMatchSnapshot(); }); - it('renders null when there are no down items', () => { + it('shallow renders null when there are no down items', () => { props.histogramSeries = []; - const component = shallowWithIntl(); + const component = shallowWithIntl(renderWithRouter()); expect(component).toEqual({}); }); - it('renders nothing if the down count has no counts', () => { + it(' shallow renders nothing if the down count has no counts', () => { props.histogramSeries = [ { timestamp: 123, @@ -64,19 +189,21 @@ describe('MonitorBarSeries component', () => { up: 0, }, ]; - const component = shallowWithIntl(); + const component = shallowWithIntl(renderWithRouter()); expect(component).toEqual({}); }); - it('renders nothing if the data series is null', () => { + it('shallow renders nothing if the data series is null', () => { const component = shallowWithIntl( - + renderWithRouter() ); expect(component).toEqual({}); }); + + it('renders if the data series is present', () => { + const component = renderWithIntl( + renderWithRouter() + ); + expect(component).toMatchSnapshot(); + }); }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx index ce91bf5b1638f4..2338bf02783485 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx @@ -19,16 +19,9 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText, EuiToolTip } from '@elastic/eui'; import { SummaryHistogramPoint } from '../../../../common/graphql/types'; import { getChartDateLabel, seriesHasDownValues } from '../../../lib/helper'; +import { useUrlParams } from '../../../hooks'; export interface MonitorBarSeriesProps { - /** - * The date/time for the start of the timespan. - */ - absoluteStartDate: number; - /** - * The date/time for the end of the timespan. - */ - absoluteEndDate: number; /** * The color to use for the display of down states. */ @@ -44,23 +37,23 @@ export interface MonitorBarSeriesProps { * so we will only render the series component if there are down counts for the selected monitor. * @param props - the values for the monitor this chart visualizes */ -export const MonitorBarSeries = ({ - absoluteStartDate, - absoluteEndDate, - dangerColor, - histogramSeries, -}: MonitorBarSeriesProps) => { +export const MonitorBarSeries = ({ dangerColor, histogramSeries }: MonitorBarSeriesProps) => { + const [getUrlParams] = useUrlParams(); + const { absoluteDateRangeStart, absoluteDateRangeEnd } = getUrlParams(); + const id = 'downSeries'; return seriesHasDownValues(histogramSeries) ? (
    - + ; -export const MonitorChartsComponent = ({ - data, - mean, - range, - monitorId, - dateRangeStart, - dateRangeEnd, - loading, -}: Props) => { - const [getUrlParams] = useUrlParams(); +export const MonitorChartsComponent = ({ data, mean, range, monitorId, loading }: Props) => { if (data && data.monitorChartsData) { const { monitorChartsData: { locationDurationLines }, } = data; - const { absoluteDateRangeStart, absoluteDateRangeEnd } = getUrlParams(); - return ( @@ -58,15 +44,7 @@ export const MonitorChartsComponent = ({ /> - + ); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap index f779efca7b18a7..3655db5aaff1ea 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap @@ -106,6 +106,560 @@ exports[`MonitorList component renders a no items message when no data is provid `; exports[`MonitorList component renders the monitor list 1`] = ` +.c1 { + padding-left: 17px; +} + +.c2 { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +@media (max-width:574px) { + .c0 { + min-width: 230px; + } +} + +
    +
    + Monitor status +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + Status + +
    +
    +
    + + Name + +
    +
    +
    + + Url + +
    +
    +
    + + Downtime history + +
    +
    +
    + +
    +
    +
    + Status +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    + 1897 Yr ago +
    +
    +
    +
    +
    +
    +
    + in 0/1 Location +
    +
    +
    +
    +
    +
    + Name +
    + +
    +
    + Url +
    +
    + +
    +
    +
    + +
    +
    + -- +
    +
    +
    +
    +
    +
    + +
    +
    +
    + Status +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    + 1895 Yr ago +
    +
    +
    +
    +
    +
    +
    + in 1/1 Location +
    +
    +
    +
    +
    +
    + Name +
    + +
    +
    + Url +
    +
    + +
    +
    +
    + +
    +
    + -- +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +`; + +exports[`MonitorList component shallow renders the monitor list 1`] = ` `; -exports[`MonitorList component renders the monitor list 1`] = ` +exports[`MonitorListPagination component renders the monitor list 1`] = ` { let result: MonitorSummaryResult; @@ -81,11 +82,9 @@ describe('MonitorList component', () => { }; }); - it('renders the monitor list', () => { + it('shallow renders the monitor list', () => { const component = shallowWithIntl( { it('renders a no items message when no data is provided', () => { const component = shallowWithIntl( { ); expect(component).toMatchSnapshot(); }); + + it('renders the monitor list', () => { + const component = renderWithIntl( + renderWithRouter( + + ) + ); + + expect(component).toMatchSnapshot(); + }); }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/monitor_list_pagination.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/monitor_list_pagination.test.tsx index a1725134094559..ff54e61006156b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/monitor_list_pagination.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/monitor_list_pagination.test.tsx @@ -13,7 +13,7 @@ import { } from '../../../../../common/graphql/types'; import { MonitorListComponent } from '../monitor_list'; -describe('MonitorList component', () => { +describe('MonitorListPagination component', () => { let result: MonitorSummaryResult; beforeEach(() => { @@ -98,8 +98,6 @@ describe('MonitorList component', () => { it('renders the monitor list', () => { const component = shallowWithIntl( { it('renders a no items message when no data is provided', () => { const component = shallowWithIntl( { - const { - absoluteStartDate, - absoluteEndDate, - dangerColor, - data, - errors, - hasActiveFilters, - linkParameters, - loading, - } = props; + const { dangerColor, data, errors, hasActiveFilters, linkParameters, loading } = props; const [drawerIds, updateDrawerIds] = useState([]); const items = data?.monitorStates?.summaries ?? []; @@ -132,12 +121,7 @@ export const MonitorListComponent = (props: Props) => { show: false, }, render: (histogramSeries: SummaryHistogramPoint[] | null) => ( - + ), }, { diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_status.bar.test.tsx.snap rename to x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_status.bar.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/monitor_status.bar.test.tsx similarity index 79% rename from x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_status.bar.test.tsx rename to x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/monitor_status.bar.test.tsx index 545405f91d5374..0a53eeb89d793f 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/monitor_status.bar.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/monitor_status.bar.test.tsx @@ -7,14 +7,12 @@ import moment from 'moment'; import React from 'react'; import { renderWithIntl } from 'test_utils/enzyme_helpers'; -import { Ping } from '../../../../common/graphql/types'; -import { MonitorStatusBarComponent } from '../monitor_status_details/monitor_status_bar'; +import { MonitorStatusBarComponent } from '../monitor_status_bar'; +import { Ping } from '../../../../../common/graphql/types'; describe('MonitorStatusBar component', () => { let monitorStatus: Ping; let monitorLocations: any; - let dateStart: string; - let dateEnd: string; beforeEach(() => { monitorStatus = { @@ -46,9 +44,6 @@ describe('MonitorStatusBar component', () => { }, ], }; - - dateStart = moment('01-01-2010').toString(); - dateEnd = moment('10-10-2010').toString(); }); it('renders duration in ms, not us', () => { @@ -56,10 +51,7 @@ describe('MonitorStatusBar component', () => { ); expect(component).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/index.ts index 7b4e1ea353c11c..385788cc825a0a 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/index.ts @@ -3,34 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { connect } from 'react-redux'; -import { AppState } from '../../../state'; -import { selectMonitorLocations } from '../../../state/selectors'; -import { fetchMonitorLocations } from '../../../state/actions/monitor'; -import { MonitorStatusDetailsComponent } from './monitor_status_details'; -const mapStateToProps = (state: AppState, { monitorId }: any) => ({ - monitorLocations: selectMonitorLocations(state, monitorId), -}); - -const mapDispatchToProps = (dispatch: any, ownProps: any) => ({ - loadMonitorLocations: () => { - const { dateStart, dateEnd, monitorId } = ownProps; - dispatch( - fetchMonitorLocations({ - monitorId, - dateStart, - dateEnd, - }) - ); - }, -}); - -export const MonitorStatusDetails = connect( - mapStateToProps, - mapDispatchToProps -)(MonitorStatusDetailsComponent); - -export * from './monitor_status_details'; -export { MonitorStatusBar } from './monitor_status_bar'; +export { MonitorStatusBarComponent } from './monitor_status_bar'; +export { MonitorStatusDetailsComponent } from './monitor_status_details'; export { StatusByLocations } from './monitor_status_bar/status_by_location'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/index.ts index 94bd7fa7f026bc..0cb11587eee480 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/index.ts @@ -4,47 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { - StateProps, - DispatchProps, - MonitorStatusBarComponent, - MonitorStatusBarProps, -} from './monitor_status_bar'; -import { selectMonitorStatus, selectMonitorLocations } from '../../../../state/selectors'; -import { AppState } from '../../../../state'; -import { getMonitorStatus, getSelectedMonitor } from '../../../../state/actions'; - -const mapStateToProps = (state: AppState, ownProps: MonitorStatusBarProps) => ({ - monitorStatus: selectMonitorStatus(state), - monitorLocations: selectMonitorLocations(state, ownProps.monitorId), -}); - -const mapDispatchToProps = (dispatch: Dispatch, ownProps: MonitorStatusBarProps) => ({ - loadMonitorStatus: () => { - const { dateStart, dateEnd, monitorId } = ownProps; - dispatch( - getMonitorStatus({ - monitorId, - dateStart, - dateEnd, - }) - ); - dispatch( - getSelectedMonitor({ - monitorId, - }) - ); - }, -}); - -// @ts-ignore TODO: Investigate typescript issues here -export const MonitorStatusBar = connect( - // @ts-ignore TODO: Investigate typescript issues here - mapStateToProps, - mapDispatchToProps -)(MonitorStatusBarComponent); - export { MonitorSSLCertificate } from './monitor_ssl_certificate'; -export * from './monitor_status_bar'; +export { MonitorStatusBarComponent } from './monitor_status_bar'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/monitor_status_bar.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/monitor_status_bar.tsx index 2524039829add1..22e4377944be13 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/monitor_status_bar.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_bar/monitor_status_bar.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; import { EuiLink, EuiTitle, @@ -13,42 +14,23 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import React, { useEffect } from 'react'; import { MonitorSSLCertificate } from './monitor_ssl_certificate'; import * as labels from './translations'; import { StatusByLocations } from './status_by_location'; import { Ping } from '../../../../../common/graphql/types'; import { MonitorLocations } from '../../../../../common/runtime_types'; -export interface StateProps { +interface MonitorStatusBarProps { + monitorId: string; monitorStatus: Ping; monitorLocations: MonitorLocations; } -export interface DispatchProps { - loadMonitorStatus: () => void; -} - -export interface MonitorStatusBarProps { - monitorId: string; - dateStart: string; - dateEnd: string; -} - -type Props = MonitorStatusBarProps & StateProps & DispatchProps; - -export const MonitorStatusBarComponent: React.FC = ({ - dateStart, - dateEnd, +export const MonitorStatusBarComponent: React.FC = ({ monitorId, - loadMonitorStatus, monitorStatus, monitorLocations, }) => { - useEffect(() => { - loadMonitorStatus(); - }, [dateStart, dateEnd, loadMonitorStatus]); - const full = monitorStatus?.url?.full ?? ''; return ( diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_details.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_details.tsx index 29bd8eb3a71837..7dea73da7bba0e 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_details.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/monitor_status_details.tsx @@ -8,16 +8,13 @@ import React, { useContext, useEffect, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import styled from 'styled-components'; import { LocationMap } from '../location_map'; -import { MonitorStatusBar } from './monitor_status_bar'; import { UptimeRefreshContext } from '../../../contexts'; +import { MonitorLocations } from '../../../../common/runtime_types'; +import { MonitorStatusBar } from '../../connected'; -interface MonitorStatusBarProps { +interface MonitorStatusDetailsProps { monitorId: string; - variables: any; - loadMonitorLocations: any; - monitorLocations: any; - dateStart: any; - dateEnd: any; + monitorLocations: MonitorLocations; } const WrapFlexItem = styled(EuiFlexItem)` @@ -28,15 +25,8 @@ const WrapFlexItem = styled(EuiFlexItem)` export const MonitorStatusDetailsComponent = ({ monitorId, - variables, - loadMonitorLocations, monitorLocations, - dateStart, - dateEnd, -}: MonitorStatusBarProps) => { - useEffect(() => { - loadMonitorLocations(monitorId); - }, [loadMonitorLocations, monitorId, dateStart, dateEnd]); +}: MonitorStatusDetailsProps) => { const { refreshApp } = useContext(UptimeRefreshContext); const [isTabActive] = useState(document.visibilityState); @@ -63,12 +53,7 @@ export const MonitorStatusDetailsComponent = ({ - + diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx index 90d716001cff96..8531cd1a3cc83d 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx @@ -5,63 +5,28 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React, { useEffect } from 'react'; +import React from 'react'; import { get } from 'lodash'; -import { connect } from 'react-redux'; -import { Snapshot as SnapshotType } from '../../../common/runtime_types'; import { DonutChart } from './charts'; -import { fetchSnapshotCount } from '../../state/actions'; import { ChartWrapper } from './charts/chart_wrapper'; import { SnapshotHeading } from './snapshot_heading'; -import { AppState } from '../../state'; +import { Snapshot as SnapshotType } from '../../../common/runtime_types'; const SNAPSHOT_CHART_WIDTH = 144; const SNAPSHOT_CHART_HEIGHT = 144; -/** - * Props expected from parent components. - */ -interface OwnProps { - dateRangeStart: string; - dateRangeEnd: string; - filters?: string; - /** - * Height is needed, since by default charts takes height of 100% - */ - height?: string; - statusFilter?: string; -} - -/** - * Props given by the Redux store based on action input. - */ -interface StoreProps { +interface SnapshotComponentProps { count: SnapshotType; - lastRefresh: number; loading: boolean; + height?: string; } /** - * Contains functions that will dispatch actions used - * for this component's life cycle - */ -interface DispatchProps { - loadSnapshotCount: typeof fetchSnapshotCount; -} - -/** - * Props used to render the Snapshot component. + * This component visualizes a KPI and histogram chart to help users quickly + * glean the status of their uptime environment. + * @param props the props required by the component */ -type Props = OwnProps & StoreProps & DispatchProps; - -type PresentationalComponentProps = Pick & - Pick; - -export const PresentationalComponent: React.FC = ({ - count, - height, - loading, -}) => ( +export const SnapshotComponent: React.FC = ({ count, height, loading }) => ( (count, 'down', 0)} total={get(count, 'total', 0)} /> @@ -73,59 +38,3 @@ export const PresentationalComponent: React.FC = ( /> ); - -/** - * This component visualizes a KPI and histogram chart to help users quickly - * glean the status of their uptime environment. - * @param props the props required by the component - */ -export const Container: React.FC = ({ - count, - dateRangeStart, - dateRangeEnd, - filters, - height, - statusFilter, - lastRefresh, - loading, - loadSnapshotCount, -}: Props) => { - useEffect(() => { - loadSnapshotCount(dateRangeStart, dateRangeEnd, filters, statusFilter); - }, [dateRangeStart, dateRangeEnd, filters, lastRefresh, loadSnapshotCount, statusFilter]); - return ; -}; - -/** - * Provides state to connected component. - * @param state the root app state - */ -const mapStateToProps = ({ - snapshot: { count, loading }, - ui: { lastRefresh }, -}: AppState): StoreProps => ({ - count, - lastRefresh, - loading, -}); - -/** - * Used for fetching snapshot counts. - * @param dispatch redux-provided action dispatcher - */ -const mapDispatchToProps = (dispatch: any) => ({ - loadSnapshotCount: ( - dateRangeStart: string, - dateRangeEnd: string, - filters?: string, - statusFilter?: string - ): DispatchProps => { - return dispatch(fetchSnapshotCount(dateRangeStart, dateRangeEnd, filters, statusFilter)); - }, -}); - -export const Snapshot = connect( - // @ts-ignore connect is expecting null | undefined for some reason - mapStateToProps, - mapDispatchToProps -)(Container); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx index 03ab9fb5cf194b..2c0be2aa15d6fb 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/status_panel.tsx @@ -4,52 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import React from 'react'; -import { Snapshot } from './snapshot'; -import { PingHistogram } from '../connected'; - -interface StatusPanelProps { - absoluteDateRangeStart: number; - absoluteDateRangeEnd: number; - dateRangeStart: string; - dateRangeEnd: string; - filters?: string; - statusFilter?: string; -} +import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import { PingHistogram, Snapshot } from '../connected'; const STATUS_CHART_HEIGHT = '160px'; -export const StatusPanel = ({ - absoluteDateRangeStart, - absoluteDateRangeEnd, - dateRangeStart, - dateRangeEnd, - filters, - statusFilter, -}: StatusPanelProps) => ( +export const StatusPanel = ({}) => ( - + - + diff --git a/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts b/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts index d02a6fc2afb5d2..8c9eec3abe2239 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts +++ b/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts @@ -55,9 +55,9 @@ export const useUpdateKueryString = ( const elasticsearchQuery = esKuery.toElasticsearchQuery(ast, indexPattern); esFilters = JSON.stringify(elasticsearchQuery); - - updateEsQueryForFilterGroup(filterQueryString, indexPattern); } + updateEsQueryForFilterGroup(filterQueryString, indexPattern); + return [esFilters]; } catch (err) { return [urlFilters, err]; diff --git a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx index 408d2584911e0d..a8501ff14313a8 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx @@ -12,8 +12,8 @@ import { UMUpdateBreadcrumbs } from '../lib/lib'; import { UptimeRefreshContext, UptimeThemeContext } from '../contexts'; import { useUptimeTelemetry, useUrlParams, UptimePage } from '../hooks'; import { useTrackPageview } from '../../../infra/public'; -import { MonitorStatusDetails } from '../components/functional/monitor_status_details'; import { PageHeader } from './page_header'; +import { MonitorStatusDetails } from '../components/connected'; interface MonitorPageProps { setBreadcrumbs: UMUpdateBreadcrumbs; @@ -49,20 +49,9 @@ export const MonitorPage = ({ setBreadcrumbs }: MonitorPageProps) => { - + - + } - + Date: Mon, 3 Feb 2020 10:12:32 -0600 Subject: [PATCH 68/69] [SIEM] Use Core HTTP Client (#54210) * Replace uses of chrome.getBasePath and fetch with core.http While core.http is coming from 'above' these functions, it doesn't make a lot of sense to pass the client through the entire stack to be able to call it at the bottom, because longer-term we'll abstract these http calls with some redux middleware. In the short term we have a mechanism to refer to core through a singleton, 'ui/new_platform', which should be around until 8.0 at least. Ideally, we'll have a more robust architecture in place by then. If not, we can reproduce the singleton module ourselves. * Fix index patterns API call core.http.fetch doesn't like a querystring in the path argument, so we move it to the query object instead. The 'type' field specifier is redundant as the type is always returned (and not as an attribute). * Refactor getIndexPatterns to use the savedObjects client We lose the updated_at field by using the client, but we weren't actually using it. I don't _think_ that the savedObjects client supports request aborts right now, but when it does we'll get that back for free. * Pass query params as object to core.http A request with query params in its path does not properly encode said params (the '?', at the very least), leading to malformed requests that result in 404s. * Remove redundant API logic This function was originally used to query both an individual rule and a list of rules, but the former functionality has been moved to fetchRuleById. * Allow throwIfNotOk to handle an undefined response This is also an error for us, and we throw as such.. * Convert new Rules APIs to use core.http These all occurred on master, this fixes them post-merge. * Refactor Signals requests expecting custom Errors These requests package up error responses in custom errors, which callers are expecting. We should refactor all of these calls to behave similarly, but for now let's just not break existing ones. * Remove default credentials specification The default is credentials: 'same-origin', and so we can omit it. * Update types in new uses of hook This savedObject type is slightly modified now that the hook is using the NP savedObjects client. * Replace explicit system header with fetch option The asSystemRequest option accomplishes the same thing without requiring us to know the implementation. With the addition of this option, setting this header explicitly causes an error. This also removes the credentials: same-origin specifier as it is the default. * Remove redundant awaits The response has previously been resolved, and so our body should be populated, here. Co-authored-by: Elastic Machine --- .../components/embeddables/__mocks__/mock.ts | 20 +- .../embeddables/embedded_map_helpers.tsx | 2 +- .../components/ml/api/anomalies_table_data.ts | 30 +-- .../components/ml/api/get_ml_capabilities.ts | 17 +- .../siem/public/components/ml_popover/api.tsx | 191 ++++++++------- .../public/components/ml_popover/types.ts | 10 - .../containers/detection_engine/rules/api.ts | 223 +++++++----------- .../detection_engine/rules/types.ts | 9 + .../detection_engine/signals/api.ts | 123 ++++------ .../siem/public/hooks/api/__mock__/api.tsx | 6 +- .../plugins/siem/public/hooks/api/api.test.ts | 4 + .../plugins/siem/public/hooks/api/api.tsx | 43 ++-- .../legacy/plugins/siem/public/hooks/types.ts | 23 +- .../siem/public/hooks/use_index_patterns.tsx | 8 +- x-pack/legacy/plugins/siem/public/plugin.tsx | 1 + 15 files changed, 299 insertions(+), 411 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts b/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts index 7834bb4511dc64..19ad0d452feb17 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts @@ -5,7 +5,7 @@ */ import { IndexPatternMapping } from '../types'; -import { IndexPatternSavedObject } from '../../ml_popover/types'; +import { IndexPatternSavedObject } from '../../../hooks/types'; export const mockIndexPatternIds: IndexPatternMapping[] = [ { title: 'filebeat-*', id: '8c7323ac-97ad-4b53-ac0a-40f8f691a918' }, @@ -425,8 +425,7 @@ export const mockLayerListMixed = [ export const mockAPMIndexPattern: IndexPatternSavedObject = { id: 'apm-*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: 'apm-*', }, @@ -435,8 +434,7 @@ export const mockAPMIndexPattern: IndexPatternSavedObject = { export const mockAPMRegexIndexPattern: IndexPatternSavedObject = { id: 'apm-7.*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: 'apm-7.*', }, @@ -445,8 +443,7 @@ export const mockAPMRegexIndexPattern: IndexPatternSavedObject = { export const mockFilebeatIndexPattern: IndexPatternSavedObject = { id: 'filebeat-*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: 'filebeat-*', }, @@ -455,8 +452,7 @@ export const mockFilebeatIndexPattern: IndexPatternSavedObject = { export const mockAuditbeatIndexPattern: IndexPatternSavedObject = { id: 'auditbeat-*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: 'auditbeat-*', }, @@ -465,8 +461,7 @@ export const mockAuditbeatIndexPattern: IndexPatternSavedObject = { export const mockAPMTransactionIndexPattern: IndexPatternSavedObject = { id: 'apm-*-transaction*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: 'apm-*-transaction*', }, @@ -475,8 +470,7 @@ export const mockAPMTransactionIndexPattern: IndexPatternSavedObject = { export const mockGlobIndexPattern: IndexPatternSavedObject = { id: '*', type: 'index-pattern', - updated_at: '', - version: 'abc', + _version: 'abc', attributes: { title: '*', }, diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map_helpers.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map_helpers.tsx index 2d4714401f3b31..e370cbbf64a4a1 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map_helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map_helpers.tsx @@ -21,7 +21,7 @@ import { getLayerList } from './map_config'; import { MAP_SAVED_OBJECT_TYPE } from '../../../../maps/common/constants'; import * as i18n from './translations'; import { Query, esFilters } from '../../../../../../../src/plugins/data/public'; -import { IndexPatternSavedObject } from '../ml_popover/types'; +import { IndexPatternSavedObject } from '../../hooks/types'; /** * Creates MapEmbeddable with provided initial configuration diff --git a/x-pack/legacy/plugins/siem/public/components/ml/api/anomalies_table_data.ts b/x-pack/legacy/plugins/siem/public/components/ml/api/anomalies_table_data.ts index 10b2538d1e7852..cb84d9182d2e01 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/api/anomalies_table_data.ts +++ b/x-pack/legacy/plugins/siem/public/components/ml/api/anomalies_table_data.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; - +import { npStart } from 'ui/new_platform'; import { Anomalies, InfluencerInput, CriteriaFields } from '../types'; import { throwIfNotOk } from '../../../hooks/api/api'; + export interface Body { jobIds: string[]; criteriaFields: CriteriaFields[]; @@ -22,17 +22,17 @@ export interface Body { } export const anomaliesTableData = async (body: Body, signal: AbortSignal): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/results/anomalies_table_data`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify(body), - headers: { - 'content-Type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - signal, - }); - await throwIfNotOk(response); - return response.json(); + const response = await npStart.core.http.fetch( + '/api/ml/results/anomalies_table_data', + { + method: 'POST', + body: JSON.stringify(body), + asResponse: true, + asSystemRequest: true, + signal, + } + ); + + await throwIfNotOk(response.response); + return response.body!; }; diff --git a/x-pack/legacy/plugins/siem/public/components/ml/api/get_ml_capabilities.ts b/x-pack/legacy/plugins/siem/public/components/ml/api/get_ml_capabilities.ts index 13339510284945..dcfd7365f8e0d5 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/api/get_ml_capabilities.ts +++ b/x-pack/legacy/plugins/siem/public/components/ml/api/get_ml_capabilities.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; import { InfluencerInput, MlCapabilities } from '../types'; import { throwIfNotOk } from '../../../hooks/api/api'; @@ -23,16 +23,13 @@ export interface Body { } export const getMlCapabilities = async (signal: AbortSignal): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/ml_capabilities`, { + const response = await npStart.core.http.fetch('/api/ml/ml_capabilities', { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-Type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, + asResponse: true, + asSystemRequest: true, signal, }); - await throwIfNotOk(response); - return response.json(); + + await throwIfNotOk(response.response); + return response.body!; }; diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/api.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/api.tsx index a04b8f4b996536..cf939d8e09b7ec 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/api.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/api.tsx @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; + import { CheckRecognizerProps, CloseJobsResponse, @@ -31,21 +32,18 @@ export const checkRecognizer = async ({ indexPatternName, signal, }: CheckRecognizerProps): Promise => { - const response = await fetch( - `${chrome.getBasePath()}/api/ml/modules/recognize/${indexPatternName}`, + const response = await npStart.core.http.fetch( + `/api/ml/modules/recognize/${indexPatternName}`, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, + asResponse: true, + asSystemRequest: true, signal, } ); - await throwIfNotOk(response); - return response.json(); + + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -55,18 +53,18 @@ export const checkRecognizer = async ({ * @param signal to cancel request */ export const getModules = async ({ moduleId = '', signal }: GetModulesProps): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/modules/get_module/${moduleId}`, { - method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - signal, - }); - await throwIfNotOk(response); - return response.json(); + const response = await npStart.core.http.fetch( + `/api/ml/modules/get_module/${moduleId}`, + { + method: 'GET', + asResponse: true, + asSystemRequest: true, + signal, + } + ); + + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -77,7 +75,6 @@ export const getModules = async ({ moduleId = '', signal }: GetModulesProps): Pr * @param jobIdErrorFilter - if provided, filters all errors except for given jobIds * @param groups - list of groups to add to jobs being installed * @param prefix - prefix to be added to job name - * @param headers optional headers to add */ export const setupMlJob = async ({ configTemplate, @@ -86,25 +83,26 @@ export const setupMlJob = async ({ groups = ['siem'], prefix = '', }: MlSetupArgs): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/modules/setup/${configTemplate}`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - prefix, - groups, - indexPatternName, - startDatafeed: false, - useDedicatedIndex: true, - }), - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - }); - await throwIfNotOk(response); - const json = await response.json(); + const response = await npStart.core.http.fetch( + `/api/ml/modules/setup/${configTemplate}`, + { + method: 'POST', + body: JSON.stringify({ + prefix, + groups, + indexPatternName, + startDatafeed: false, + useDedicatedIndex: true, + }), + asResponse: true, + asSystemRequest: true, + } + ); + + await throwIfNotOk(response.response); + const json = response.body!; throwIfErrorAttachedToSetup(json, jobIdErrorFilter); + return json; }; @@ -121,22 +119,23 @@ export const startDatafeeds = async ({ datafeedIds: string[]; start: number; }): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/jobs/force_start_datafeeds`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - datafeedIds, - ...(start !== 0 && { start }), - }), - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - }); - await throwIfNotOk(response); - const json = await response.json(); + const response = await npStart.core.http.fetch( + '/api/ml/jobs/force_start_datafeeds', + { + method: 'POST', + body: JSON.stringify({ + datafeedIds, + ...(start !== 0 && { start }), + }), + asResponse: true, + asSystemRequest: true, + } + ); + + await throwIfNotOk(response.response); + const json = response.body!; throwIfErrorAttached(json, datafeedIds); + return json; }; @@ -144,49 +143,46 @@ export const startDatafeeds = async ({ * Stops the given dataFeedIds and sets the corresponding Job's jobState to closed * * @param datafeedIds - * @param headers optional headers to add */ export const stopDatafeeds = async ({ datafeedIds, }: { datafeedIds: string[]; }): Promise<[StopDatafeedResponse | ErrorResponse, CloseJobsResponse]> => { - const stopDatafeedsResponse = await fetch(`${chrome.getBasePath()}/api/ml/jobs/stop_datafeeds`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - datafeedIds, - }), - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - }); + const stopDatafeedsResponse = await npStart.core.http.fetch( + '/api/ml/jobs/stop_datafeeds', + { + method: 'POST', + body: JSON.stringify({ + datafeedIds, + }), + asResponse: true, + asSystemRequest: true, + } + ); - await throwIfNotOk(stopDatafeedsResponse); - const stopDatafeedsResponseJson = await stopDatafeedsResponse.json(); + await throwIfNotOk(stopDatafeedsResponse.response); + const stopDatafeedsResponseJson = stopDatafeedsResponse.body!; const datafeedPrefix = 'datafeed-'; - const closeJobsResponse = await fetch(`${chrome.getBasePath()}/api/ml/jobs/close_jobs`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - jobIds: datafeedIds.map(dataFeedId => - dataFeedId.startsWith(datafeedPrefix) - ? dataFeedId.substring(datafeedPrefix.length) - : dataFeedId - ), - }), - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - }); + const closeJobsResponse = await npStart.core.http.fetch( + '/api/ml/jobs/close_jobs', + { + method: 'POST', + body: JSON.stringify({ + jobIds: datafeedIds.map(dataFeedId => + dataFeedId.startsWith(datafeedPrefix) + ? dataFeedId.substring(datafeedPrefix.length) + : dataFeedId + ), + }), + asResponse: true, + asSystemRequest: true, + } + ); - await throwIfNotOk(closeJobsResponse); - return [stopDatafeedsResponseJson, await closeJobsResponse.json()]; + await throwIfNotOk(closeJobsResponse.response); + return [stopDatafeedsResponseJson, closeJobsResponse.body!]; }; /** @@ -198,17 +194,14 @@ export const stopDatafeeds = async ({ * @param signal to cancel request */ export const getJobsSummary = async (signal: AbortSignal): Promise => { - const response = await fetch(`${chrome.getBasePath()}/api/ml/jobs/jobs_summary`, { + const response = await npStart.core.http.fetch('/api/ml/jobs/jobs_summary', { method: 'POST', - credentials: 'same-origin', body: JSON.stringify({}), - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, + asResponse: true, + asSystemRequest: true, signal, }); - await throwIfNotOk(response); - return response.json(); + + await throwIfNotOk(response.response); + return response.body!; }; diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/types.ts b/x-pack/legacy/plugins/siem/public/components/ml_popover/types.ts index 964ae8c8242d4b..f3bf78fdbb94c5 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/types.ts @@ -193,16 +193,6 @@ export interface CloseJobsResponse { }; } -export interface IndexPatternSavedObject { - attributes: { - title: string; - }; - id: string; - type: string; - updated_at: string; - version: string; -} - export interface JobsFilters { filterQuery: string; showCustomJobs: boolean; diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts index 8f4abeb31c2269..4f50a9bd147881 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; + import { AddRulesProps, DeleteRulesProps, @@ -19,8 +20,9 @@ import { ImportRulesProps, ExportRulesProps, RuleError, - RuleStatus, + RuleStatusResponse, ImportRulesResponse, + PrePackagedRulesStatusResponse, } from './types'; import { throwIfNotOk } from '../../../hooks/api/api'; import { @@ -39,19 +41,15 @@ import * as i18n from '../../../pages/detection_engine/rules/translations'; * @param signal to cancel request */ export const addRule = async ({ rule, signal }: AddRulesProps): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}`, { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_RULES_URL, { method: rule.id != null ? 'PUT' : 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, body: JSON.stringify(rule), + asResponse: true, signal, }); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -79,40 +77,36 @@ export const fetchRules = async ({ signal, }: FetchRulesProps): Promise => { const filters = [ - ...(filterOptions.filter.length !== 0 - ? [`alert.attributes.name:%20${encodeURIComponent(filterOptions.filter)}`] - : []), + ...(filterOptions.filter.length ? [`alert.attributes.name: ${filterOptions.filter}`] : []), ...(filterOptions.showCustomRules - ? ['alert.attributes.tags:%20%22__internal_immutable:false%22'] + ? [`alert.attributes.tags: "__internal_immutable:false"`] : []), ...(filterOptions.showElasticRules - ? ['alert.attributes.tags:%20%22__internal_immutable:true%22'] + ? [`alert.attributes.tags: "__internal_immutable:true"`] : []), - ...(filterOptions.tags?.map(t => `alert.attributes.tags:${encodeURIComponent(t)}`) ?? []), + ...(filterOptions.tags?.map(t => `alert.attributes.tags: ${t}`) ?? []), ]; - const queryParams = [ - `page=${pagination.page}`, - `per_page=${pagination.perPage}`, - `sort_field=${filterOptions.sortField}`, - `sort_order=${filterOptions.sortOrder}`, - ...(filters.length > 0 ? [`filter=${filters.join('%20AND%20')}`] : []), - ]; + const query = { + page: pagination.page, + per_page: pagination.perPage, + sort_field: filterOptions.sortField, + sort_order: filterOptions.sortOrder, + ...(filters.length ? { filter: filters.join(' AND ') } : {}), + }; - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_find?${queryParams.join('&')}`, + const response = await npStart.core.http.fetch( + `${DETECTION_ENGINE_RULES_URL}/_find`, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, + query, signal, + asResponse: true, } ); - await throwIfNotOk(response); - return response.json(); + + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -123,18 +117,15 @@ export const fetchRules = async ({ * */ export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}?id=${id}`, { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, + query: { id }, + asResponse: true, signal, }); - await throwIfNotOk(response); - const rule: Rule = await response.json(); - return rule; + + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -146,21 +137,17 @@ export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise => { - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_bulk_update`, + const response = await npStart.core.http.fetch( + `${DETECTION_ENGINE_RULES_URL}/_bulk_update`, { method: 'PUT', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, body: JSON.stringify(ids.map(id => ({ id, enabled }))), + asResponse: true, } ); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -171,21 +158,17 @@ export const enableRules = async ({ ids, enabled }: EnableRulesProps): Promise> => { - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_bulk_delete`, + const response = await npStart.core.http.fetch( + `${DETECTION_ENGINE_RULES_URL}/_bulk_delete`, { - method: 'DELETE', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, + method: 'PUT', body: JSON.stringify(ids.map(id => ({ id }))), + asResponse: true, } ); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -194,15 +177,10 @@ export const deleteRules = async ({ ids }: DeleteRulesProps): Promise => { - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_bulk_create`, + const response = await npStart.core.http.fetch( + `${DETECTION_ENGINE_RULES_URL}/_bulk_create`, { method: 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, body: JSON.stringify( rules.map(rule => ({ ...rule, @@ -223,11 +201,12 @@ export const duplicateRules = async ({ rules }: DuplicateRulesProps): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_PREPACKAGED_URL}`, { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_PREPACKAGED_URL, { method: 'PUT', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, signal, + asResponse: true, }); - await throwIfNotOk(response); + + await throwIfNotOk(response.response); return true; }; @@ -266,21 +242,19 @@ export const importRules = async ({ const formData = new FormData(); formData.append('file', fileToImport); - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_import?overwrite=${overwrite}`, + const response = await npStart.core.http.fetch( + `${DETECTION_ENGINE_RULES_URL}/_import`, { method: 'POST', - credentials: 'same-origin', - headers: { - 'kbn-xsrf': 'true', - }, + query: { overwrite }, body: formData, + asResponse: true, signal, } ); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -304,24 +278,19 @@ export const exportRules = async ({ ? JSON.stringify({ objects: ruleIds.map(rule => ({ rule_id: rule })) }) : undefined; - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_export?exclude_export_details=${excludeExportDetails}&file_name=${encodeURIComponent( - filename - )}`, - { - method: 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, - body, - signal, - } - ); + const response = await npStart.core.http.fetch(`${DETECTION_ENGINE_RULES_URL}/_export`, { + method: 'POST', + body, + query: { + exclude_export_details: excludeExportDetails, + file_name: filename, + }, + signal, + asResponse: true, + }); - await throwIfNotOk(response); - return response.blob(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -338,24 +307,19 @@ export const getRuleStatusById = async ({ }: { id: string; signal: AbortSignal; -}): Promise> => { - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_STATUS_URL}?ids=${encodeURIComponent( - JSON.stringify([id]) - )}`, +}): Promise => { + const response = await npStart.core.http.fetch( + DETECTION_ENGINE_RULES_STATUS_URL, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, + query: { ids: JSON.stringify([id]) }, signal, + asResponse: true, } ); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -365,18 +329,14 @@ export const getRuleStatusById = async ({ * */ export const fetchTags = async ({ signal }: { signal: AbortSignal }): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_TAGS_URL}`, { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_TAGS_URL, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, signal, + asResponse: true, }); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -390,25 +350,16 @@ export const getPrePackagedRulesStatus = async ({ signal, }: { signal: AbortSignal; -}): Promise<{ - rules_custom_installed: number; - rules_installed: number; - rules_not_installed: number; - rules_not_updated: number; -}> => { - const response = await fetch( - `${chrome.getBasePath()}${DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL}`, +}): Promise => { + const response = await npStart.core.http.fetch( + DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, signal, + asResponse: true, } ); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts index b30c3b211b1b8d..0aaffb7b86b284 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts @@ -197,3 +197,12 @@ export interface RuleInfoStatus { last_failure_message: string | null; last_success_message: string | null; } + +export type RuleStatusResponse = Record; + +export interface PrePackagedRulesStatusResponse { + rules_custom_installed: number; + rules_installed: number; + rules_not_installed: number; + rules_not_updated: number; +} diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/api.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/api.ts index 8754d73637e7c7..d0da70e6461248 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/api.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; import { throwIfNotOk } from '../../../hooks/api/api'; import { @@ -14,40 +14,37 @@ import { DETECTION_ENGINE_PRIVILEGES_URL, } from '../../../../common/constants'; import { + BasicSignals, + PostSignalError, + Privilege, QuerySignals, + SignalIndexError, SignalSearchResponse, - UpdateSignalStatusProps, SignalsIndex, - SignalIndexError, - Privilege, - PostSignalError, - BasicSignals, + UpdateSignalStatusProps, } from './types'; -import { parseJsonFromBody } from '../../../utils/api'; /** * Fetch Signals by providing a query * * @param query String to match a dsl - * @param signal AbortSignal for cancelling request */ export const fetchQuerySignals = async ({ query, signal, }: QuerySignals): Promise> => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_QUERY_SIGNALS_URL}`, { - method: 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, - body: JSON.stringify(query), - signal, - }); - await throwIfNotOk(response); - const signals = await response.json(); - return signals; + const response = await npStart.core.http.fetch>( + DETECTION_ENGINE_QUERY_SIGNALS_URL, + { + method: 'POST', + body: JSON.stringify(query), + asResponse: true, + signal, + } + ); + + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -62,19 +59,15 @@ export const updateSignalStatus = async ({ status, signal, }: UpdateSignalStatusProps): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_SIGNALS_STATUS_URL}`, { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_SIGNALS_STATUS_URL, { method: 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, body: JSON.stringify({ status, ...query }), + asResponse: true, signal, }); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -82,25 +75,18 @@ export const updateSignalStatus = async ({ * * @param signal AbortSignal for cancelling request */ -export const getSignalIndex = async ({ signal }: BasicSignals): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_INDEX_URL}`, { - method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, - signal, - }); - if (response.ok) { - const signalIndex = await response.json(); - return signalIndex; +export const getSignalIndex = async ({ signal }: BasicSignals): Promise => { + try { + return await npStart.core.http.fetch(DETECTION_ENGINE_INDEX_URL, { + method: 'GET', + signal, + }); + } catch (e) { + if (e.body) { + throw new SignalIndexError(e.body); + } + throw e; } - const error = await parseJsonFromBody(response); - if (error != null) { - throw new SignalIndexError(error); - } - return null; }; /** @@ -108,19 +94,15 @@ export const getSignalIndex = async ({ signal }: BasicSignals): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_PRIVILEGES_URL}`, { +export const getUserPrivilege = async ({ signal }: BasicSignals): Promise => { + const response = await npStart.core.http.fetch(DETECTION_ENGINE_PRIVILEGES_URL, { method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, signal, + asResponse: true, }); - await throwIfNotOk(response); - return response.json(); + await throwIfNotOk(response.response); + return response.body!; }; /** @@ -128,23 +110,16 @@ export const getUserPrivilege = async ({ signal }: BasicSignals): Promise => { - const response = await fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_INDEX_URL}`, { - method: 'POST', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-xsrf': 'true', - }, - signal, - }); - if (response.ok) { - const signalIndex = await response.json(); - return signalIndex; - } - const error = await parseJsonFromBody(response); - if (error != null) { - throw new PostSignalError(error); +export const createSignalIndex = async ({ signal }: BasicSignals): Promise => { + try { + return await npStart.core.http.fetch(DETECTION_ENGINE_INDEX_URL, { + method: 'POST', + signal, + }); + } catch (e) { + if (e.body) { + throw new PostSignalError(e.body); + } + throw e; } - return null; }; diff --git a/x-pack/legacy/plugins/siem/public/hooks/api/__mock__/api.tsx b/x-pack/legacy/plugins/siem/public/hooks/api/__mock__/api.tsx index 13f53cd34feb62..b12b04e8f760b5 100644 --- a/x-pack/legacy/plugins/siem/public/hooks/api/__mock__/api.tsx +++ b/x-pack/legacy/plugins/siem/public/hooks/api/__mock__/api.tsx @@ -13,8 +13,7 @@ export const mockIndexPatternSavedObjects: IndexPatternSavedObject[] = [ attributes: { title: 'filebeat-*', }, - updated_at: '2019-08-26T04:30:09.111Z', - version: 'WzE4LLwxXQ==', + _version: 'WzE4LLwxXQ==', }, { type: 'index-pattern', @@ -22,7 +21,6 @@ export const mockIndexPatternSavedObjects: IndexPatternSavedObject[] = [ attributes: { title: 'auditbeat-*', }, - updated_at: '2019-08-26T04:31:12.934Z', - version: 'WzELLywxXQ==', + _version: 'WzELLywxXQ==', }, ]; diff --git a/x-pack/legacy/plugins/siem/public/hooks/api/api.test.ts b/x-pack/legacy/plugins/siem/public/hooks/api/api.test.ts index 95825b7d4abda5..208a3b14ca283c 100644 --- a/x-pack/legacy/plugins/siem/public/hooks/api/api.test.ts +++ b/x-pack/legacy/plugins/siem/public/hooks/api/api.test.ts @@ -13,6 +13,10 @@ describe('api', () => { }); describe('#throwIfNotOk', () => { + test('throws a network error if there is no response', async () => { + await expect(throwIfNotOk()).rejects.toThrow('Network Error'); + }); + test('does a throw if it is given response that is not ok and the body is not parsable', async () => { fetchMock.mock('http://example.com', 500); const response = await fetch('http://example.com'); diff --git a/x-pack/legacy/plugins/siem/public/hooks/api/api.tsx b/x-pack/legacy/plugins/siem/public/hooks/api/api.tsx index 8d319ffe239027..f5f32da7d8c0b2 100644 --- a/x-pack/legacy/plugins/siem/public/hooks/api/api.tsx +++ b/x-pack/legacy/plugins/siem/public/hooks/api/api.tsx @@ -4,46 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; - +import { npStart } from 'ui/new_platform'; import * as i18n from '../translations'; import { parseJsonFromBody, ToasterErrors } from '../../components/ml/api/throw_if_not_ok'; -import { IndexPatternResponse, IndexPatternSavedObject } from '../types'; - -const emptyIndexPattern: IndexPatternSavedObject[] = []; +import { IndexPatternSavedObject, IndexPatternSavedObjectAttributes } from '../types'; /** * Fetches Configured Index Patterns from the Kibana saved objects API * * TODO: Refactor to context provider: https://github.com/elastic/siem-team/issues/448 - * - * @param signal */ -export const getIndexPatterns = async (signal: AbortSignal): Promise => { - const response = await fetch( - `${chrome.getBasePath()}/api/saved_objects/_find?type=index-pattern&fields=title&fields=type&per_page=10000`, - { - method: 'GET', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json', - 'kbn-system-api': 'true', - 'kbn-xsrf': 'true', - }, - signal, - } - ); - await throwIfNotOk(response); - const results: IndexPatternResponse = await response.json(); +export const getIndexPatterns = async (): Promise => { + const response = await npStart.core.savedObjects.client.find({ + type: 'index-pattern', + fields: ['title'], + perPage: 10000, + }); - if (results.saved_objects && Array.isArray(results.saved_objects)) { - return results.saved_objects; - } else { - return emptyIndexPattern; - } + return response.savedObjects; }; -export const throwIfNotOk = async (response: Response): Promise => { +export const throwIfNotOk = async (response?: Response): Promise => { + if (!response) { + throw new ToasterErrors([i18n.NETWORK_ERROR]); + } + if (!response.ok) { const body = await parseJsonFromBody(response); if (body != null && body.message) { diff --git a/x-pack/legacy/plugins/siem/public/hooks/types.ts b/x-pack/legacy/plugins/siem/public/hooks/types.ts index 4d66d8e1912352..301b8bd6553337 100644 --- a/x-pack/legacy/plugins/siem/public/hooks/types.ts +++ b/x-pack/legacy/plugins/siem/public/hooks/types.ts @@ -4,19 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface IndexPatternSavedObject { - attributes: { - title: string; - }; - id: string; - type: string; - updated_at: string; - version: string; -} +import { SimpleSavedObject } from '../../../../../../src/core/public'; -export interface IndexPatternResponse { - page: number; - per_page: number; - saved_objects: IndexPatternSavedObject[]; - total: number; -} +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type IndexPatternSavedObjectAttributes = { title: string }; + +export type IndexPatternSavedObject = Pick< + SimpleSavedObject, + 'type' | 'id' | 'attributes' | '_version' +>; diff --git a/x-pack/legacy/plugins/siem/public/hooks/use_index_patterns.tsx b/x-pack/legacy/plugins/siem/public/hooks/use_index_patterns.tsx index 7abe88402096c8..35bed69e8617eb 100644 --- a/x-pack/legacy/plugins/siem/public/hooks/use_index_patterns.tsx +++ b/x-pack/legacy/plugins/siem/public/hooks/use_index_patterns.tsx @@ -8,10 +8,10 @@ import { useEffect, useState } from 'react'; import { useStateToaster } from '../components/toasters'; import { errorToToaster } from '../components/ml/api/error_to_toaster'; -import { IndexPatternSavedObject } from '../components/ml_popover/types'; -import { getIndexPatterns } from './api/api'; import * as i18n from './translations'; +import { IndexPatternSavedObject } from './types'; +import { getIndexPatterns } from './api/api'; type Return = [boolean, IndexPatternSavedObject[]]; @@ -22,12 +22,11 @@ export const useIndexPatterns = (refreshToggle = false): Return => { useEffect(() => { let isSubscribed = true; - const abortCtrl = new AbortController(); setIsLoading(true); async function fetchIndexPatterns() { try { - const data = await getIndexPatterns(abortCtrl.signal); + const data = await getIndexPatterns(); if (isSubscribed) { setIndexPatterns(data); @@ -44,7 +43,6 @@ export const useIndexPatterns = (refreshToggle = false): Return => { fetchIndexPatterns(); return () => { isSubscribed = false; - abortCtrl.abort(); }; }, [refreshToggle]); diff --git a/x-pack/legacy/plugins/siem/public/plugin.tsx b/x-pack/legacy/plugins/siem/public/plugin.tsx index 7911b5eb9833b4..74fc913d2b573a 100644 --- a/x-pack/legacy/plugins/siem/public/plugin.tsx +++ b/x-pack/legacy/plugins/siem/public/plugin.tsx @@ -41,6 +41,7 @@ export type Start = ReturnType; export class Plugin implements IPlugin { public id = 'siem'; public name = 'SIEM'; + constructor( // @ts-ignore this is added to satisfy the New Platform typing constraint, // but we're not leveraging any of its functionality yet. From 4f4d3d753c0fef8df7e4ac242d5f15609af243b8 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Mon, 3 Feb 2020 11:19:41 -0500 Subject: [PATCH 69/69] [Lens] Fix bugs in Lens filters (#56441) * [Lens] Fix bug where filters were not displayed * Fix #55603 Co-authored-by: Elastic Machine --- .../lens/public/app_plugin/app.test.tsx | 24 +++++++++++++++---- .../plugins/lens/public/app_plugin/app.tsx | 7 +++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 80a7ceb61c324c..99926c646da223 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -60,10 +60,14 @@ function createMockFilterManager() { return unsubscribe; }, }), - setFilters: (newFilters: unknown[]) => { + setFilters: jest.fn((newFilters: unknown[]) => { filters = newFilters; - subscriber(); - }, + if (subscriber) subscriber(); + }), + setAppFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), getFilters: () => filters, getGlobalFilters: () => { // @ts-ignore @@ -189,6 +193,13 @@ describe('Lens App', () => { `); }); + it('clears app filters on load', () => { + const defaultArgs = makeDefaultArgs(); + mount(); + + expect(defaultArgs.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([]); + }); + it('sets breadcrumbs when the document title changes', async () => { const defaultArgs = makeDefaultArgs(); const instance = mount(); @@ -226,7 +237,7 @@ describe('Lens App', () => { expect(args.docStorage.load).not.toHaveBeenCalled(); }); - it('loads a document and uses query if there is a document id', async () => { + it('loads a document and uses query and filters if there is a document id', async () => { const args = makeDefaultArgs(); args.editorFrame = frame; (args.docStorage.load as jest.Mock).mockResolvedValue({ @@ -234,6 +245,7 @@ describe('Lens App', () => { expression: 'valid expression', state: { query: 'fake query', + filters: [{ query: { match_phrase: { src: 'test' } } }], datasourceMetaData: { filterableIndexPatterns: [{ id: '1', title: 'saved' }] }, }, }); @@ -245,6 +257,9 @@ describe('Lens App', () => { expect(args.docStorage.load).toHaveBeenCalledWith('1234'); expect(args.data.indexPatterns.get).toHaveBeenCalledWith('1'); + expect(args.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ + { query: { match_phrase: { src: 'test' } } }, + ]); expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', @@ -260,6 +275,7 @@ describe('Lens App', () => { expression: 'valid expression', state: { query: 'fake query', + filters: [{ query: { match_phrase: { src: 'test' } } }], datasourceMetaData: { filterableIndexPatterns: [{ id: '1', title: 'saved' }] }, }, }, diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index 35e45af6a3d689..6d2ebee1d88dbe 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -83,6 +83,10 @@ export function App({ const { lastKnownDoc } = state; useEffect(() => { + // Clear app-specific filters when navigating to Lens. Necessary because Lens + // can be loaded without a full page refresh + data.query.filterManager.setAppFilters([]); + const filterSubscription = data.query.filterManager.getUpdates$().subscribe({ next: () => { setState(s => ({ ...s, filters: data.query.filterManager.getFilters() })); @@ -123,13 +127,14 @@ export function App({ core.notifications ) .then(indexPatterns => { + // Don't overwrite any pinned filters + data.query.filterManager.setAppFilters(doc.state.filters); setState(s => ({ ...s, isLoading: false, persistedDoc: doc, lastKnownDoc: doc, query: doc.state.query, - filters: doc.state.filters, indexPatternsForTopNav: indexPatterns, })); })