From 5ff38a122b7fb4b0c77f9b3bbc43c6878ebb060c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 11 Oct 2021 13:10:52 +0100 Subject: [PATCH 01/73] skip failing es promotion suites (#114471) --- x-pack/test/api_integration/apis/maps/get_tile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/apis/maps/get_tile.js b/x-pack/test/api_integration/apis/maps/get_tile.js index 03a16175931a5..b153cc1ff030c 100644 --- a/x-pack/test/api_integration/apis/maps/get_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_tile.js @@ -13,7 +13,8 @@ import { MVT_SOURCE_LAYER_NAME } from '../../../../plugins/maps/common/constants export default function ({ getService }) { const supertest = getService('supertest'); - describe('getTile', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/114471 + describe.skip('getTile', () => { it('should return vector tile containing document', async () => { const resp = await supertest .get( From 76546920fc3daab9fb3ddb891e1973775f4c61aa Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 11 Oct 2021 13:17:33 +0100 Subject: [PATCH 02/73] skip failing es promotion suites (#114473, #114474) --- .../functional/apps/index_lifecycle_management/home_page.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/index_lifecycle_management/home_page.ts b/x-pack/test/functional/apps/index_lifecycle_management/home_page.ts index c51e2968baee0..e2540d80280c2 100644 --- a/x-pack/test/functional/apps/index_lifecycle_management/home_page.ts +++ b/x-pack/test/functional/apps/index_lifecycle_management/home_page.ts @@ -16,7 +16,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const retry = getService('retry'); const esClient = getService('es'); - describe('Home page', function () { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/114473 and https://github.com/elastic/kibana/issues/114474 + describe.skip('Home page', function () { before(async () => { await pageObjects.common.navigateToApp('indexLifecycleManagement'); }); From c34e99ee73ede89c3425dfdd13ad05747637c4b7 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 11 Oct 2021 13:37:04 +0100 Subject: [PATCH 03/73] skip flaky suites (#100951) --- .../__jest__/client_integration/follower_indices_list.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js index b9e47b029e302..bcd4aaf82eeb3 100644 --- a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js @@ -314,7 +314,8 @@ describe('', () => { }); }); - describe('detail panel', () => { + // FLAKY: https://github.com/elastic/kibana/issues/100951 + describe.skip('detail panel', () => { test('should open a detail panel when clicking on a follower index', async () => { expect(exists('followerIndexDetail')).toBe(false); From f2bfa595ee4cbc4cdea33947f8c539c40ffbf1ed Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 11 Oct 2021 13:50:27 +0100 Subject: [PATCH 04/73] skip flaky suite (#106053) --- .../test/functional/apps/ml/anomaly_detection/custom_urls.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts b/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts index 0dcb767309608..7d4df75ccdcf7 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts @@ -81,7 +81,8 @@ export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); const browser = getService('browser'); - describe('custom urls', function () { + // FLAKY: https://github.com/elastic/kibana/issues/106053 + describe.skip('custom urls', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); From 2ffbf6e58eadade0bb9b5386de7d3406d3cc5ae8 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 11 Oct 2021 15:20:27 +0200 Subject: [PATCH 05/73] [Security Solution] Add host isolation exception IPs UI (#113762) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../host_isolation_exceptions/service.ts | 14 ++ .../host_isolation_exceptions/store/action.ts | 17 +- .../store/builders.ts | 4 + .../store/middleware.test.ts | 80 ++++++- .../store/middleware.ts | 46 +++- .../store/reducer.test.ts | 10 + .../store/reducer.ts | 18 ++ .../pages/host_isolation_exceptions/types.ts | 5 + .../pages/host_isolation_exceptions/utils.ts | 41 ++++ .../view/components/empty.tsx | 12 +- .../view/components/form.test.tsx | 75 +++++++ .../view/components/form.tsx | 206 ++++++++++++++++++ .../view/components/form_flyout.test.tsx | 114 ++++++++++ .../view/components/form_flyout.tsx | 180 +++++++++++++++ .../view/components/translations.ts | 64 ++++++ .../host_isolation_exceptions_list.test.tsx | 22 +- .../view/host_isolation_exceptions_list.tsx | 33 ++- 17 files changed, 925 insertions(+), 16 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/utils.ts create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts index 79ca595fbb61b..8af353a3c9531 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts @@ -6,6 +6,7 @@ */ import { + CreateExceptionListItemSchema, ExceptionListItemSchema, FoundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; @@ -65,6 +66,19 @@ export async function getHostIsolationExceptionItems({ return entries; } +export async function createHostIsolationExceptionItem({ + http, + exception, +}: { + http: HttpStart; + exception: CreateExceptionListItemSchema; +}): Promise { + await ensureHostIsolationExceptionsListExists(http); + return http.post(EXCEPTION_LIST_ITEM_URL, { + body: JSON.stringify(exception), + }); +} + export async function deleteHostIsolationExceptionItems(http: HttpStart, id: string) { await ensureHostIsolationExceptionsListExists(http); return http.delete(EXCEPTION_LIST_ITEM_URL, { diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts index 0a9f776655371..a5fae36486f98 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts @@ -14,6 +14,20 @@ export type HostIsolationExceptionsPageDataChanged = payload: HostIsolationExceptionsPageState['entries']; }; +export type HostIsolationExceptionsFormStateChanged = + Action<'hostIsolationExceptionsFormStateChanged'> & { + payload: HostIsolationExceptionsPageState['form']['status']; + }; + +export type HostIsolationExceptionsFormEntryChanged = + Action<'hostIsolationExceptionsFormEntryChanged'> & { + payload: HostIsolationExceptionsPageState['form']['entry']; + }; + +export type HostIsolationExceptionsCreateEntry = Action<'hostIsolationExceptionsCreateEntry'> & { + payload: HostIsolationExceptionsPageState['form']['entry']; +}; + export type HostIsolationExceptionsDeleteItem = Action<'hostIsolationExceptionsMarkToDelete'> & { payload?: ExceptionListItemSchema; }; @@ -24,9 +38,10 @@ export type HostIsolationExceptionsDeleteStatusChanged = Action<'hostIsolationExceptionsDeleteStatusChanged'> & { payload: HostIsolationExceptionsPageState['deletion']['status']; }; - export type HostIsolationExceptionsPageAction = | HostIsolationExceptionsPageDataChanged + | HostIsolationExceptionsCreateEntry + | HostIsolationExceptionsFormStateChanged | HostIsolationExceptionsDeleteItem | HostIsolationExceptionsSubmitDelete | HostIsolationExceptionsDeleteStatusChanged; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/builders.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/builders.ts index 68a50f9c813f4..8f32d9cf8d456 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/builders.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/builders.ts @@ -16,6 +16,10 @@ export const initialHostIsolationExceptionsPageState = (): HostIsolationExceptio page_size: MANAGEMENT_DEFAULT_PAGE_SIZE, filter: '', }, + form: { + entry: undefined, + status: createUninitialisedResourceState(), + }, deletion: { item: undefined, status: createUninitialisedResourceState(), diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts index 984794e074ebb..266853fdab5e2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts @@ -5,10 +5,11 @@ * 2.0. */ +import { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { applyMiddleware, createStore, Store } from 'redux'; -import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; import { coreMock } from '../../../../../../../../src/core/public/mocks'; import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; +import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; import { AppAction } from '../../../../common/store/actions'; import { createSpyMiddleware, @@ -19,8 +20,13 @@ import { isLoadedResourceState, isLoadingResourceState, } from '../../../state'; -import { getHostIsolationExceptionItems, deleteHostIsolationExceptionItems } from '../service'; +import { + createHostIsolationExceptionItem, + deleteHostIsolationExceptionItems, + getHostIsolationExceptionItems, +} from '../service'; import { HostIsolationExceptionsPageState } from '../types'; +import { createEmptyHostIsolationException } from '../utils'; import { initialHostIsolationExceptionsPageState } from './builders'; import { createHostIsolationExceptionsPageMiddleware } from './middleware'; import { hostIsolationExceptionsPageReducer } from './reducer'; @@ -29,6 +35,7 @@ import { getListFetchError } from './selector'; jest.mock('../service'); const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; const deleteHostIsolationExceptionItemsMock = deleteHostIsolationExceptionItems as jest.Mock; +const createHostIsolationExceptionItemMock = createHostIsolationExceptionItem as jest.Mock; const fakeCoreStart = coreMock.createStart({ basePath: '/mock' }); @@ -81,7 +88,7 @@ describe('Host isolation exceptions middleware', () => { }; beforeEach(() => { - getHostIsolationExceptionItemsMock.mockClear(); + getHostIsolationExceptionItemsMock.mockReset(); getHostIsolationExceptionItemsMock.mockImplementation(getFoundExceptionListItemSchemaMock); }); @@ -145,11 +152,74 @@ describe('Host isolation exceptions middleware', () => { }); }); + describe('When adding an item to host isolation exceptions', () => { + let entry: CreateExceptionListItemSchema; + beforeEach(() => { + createHostIsolationExceptionItemMock.mockReset(); + entry = { + ...createEmptyHostIsolationException(), + name: 'test name', + description: 'description', + entries: [ + { + field: 'destination.ip', + operator: 'included', + type: 'match', + value: '10.0.0.1', + }, + ], + }; + }); + it('should dispatch a form loading state when an entry is submited', async () => { + const waiter = spyMiddleware.waitForAction('hostIsolationExceptionsFormStateChanged', { + validate({ payload }) { + return isLoadingResourceState(payload); + }, + }); + store.dispatch({ + type: 'hostIsolationExceptionsCreateEntry', + payload: entry, + }); + await waiter; + }); + it('should dispatch a form success state when an entry is confirmed by the API', async () => { + const waiter = spyMiddleware.waitForAction('hostIsolationExceptionsFormStateChanged', { + validate({ payload }) { + return isLoadedResourceState(payload); + }, + }); + store.dispatch({ + type: 'hostIsolationExceptionsCreateEntry', + payload: entry, + }); + await waiter; + expect(createHostIsolationExceptionItemMock).toHaveBeenCalledWith({ + http: fakeCoreStart.http, + exception: entry, + }); + }); + it('should dispatch a form failure state when an entry is rejected by the API', async () => { + createHostIsolationExceptionItemMock.mockRejectedValue({ + body: { message: 'error message', statusCode: 500, error: 'Not today' }, + }); + const waiter = spyMiddleware.waitForAction('hostIsolationExceptionsFormStateChanged', { + validate({ payload }) { + return isFailedResourceState(payload); + }, + }); + store.dispatch({ + type: 'hostIsolationExceptionsCreateEntry', + payload: entry, + }); + await waiter; + }); + }); + describe('When deleting an item from host isolation exceptions', () => { beforeEach(() => { - deleteHostIsolationExceptionItemsMock.mockClear(); + deleteHostIsolationExceptionItemsMock.mockReset(); deleteHostIsolationExceptionItemsMock.mockReturnValue(undefined); - getHostIsolationExceptionItemsMock.mockClear(); + getHostIsolationExceptionItemsMock.mockReset(); getHostIsolationExceptionItemsMock.mockImplementation(getFoundExceptionListItemSchemaMock); store.dispatch({ type: 'hostIsolationExceptionsMarkToDelete', diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts index 4946cac488700..bbc754e8155b0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts @@ -6,11 +6,13 @@ */ import { + CreateExceptionListItemSchema, ExceptionListItemSchema, FoundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import { CoreStart, HttpSetup, HttpStart } from 'kibana/public'; import { matchPath } from 'react-router-dom'; +import { transformNewItemOutput } from '@kbn/securitysolution-list-hooks'; import { AppLocation, Immutable } from '../../../../../common/endpoint/types'; import { ImmutableMiddleware, ImmutableMiddlewareAPI } from '../../../../common/store'; import { AppAction } from '../../../../common/store/actions'; @@ -20,7 +22,11 @@ import { createFailedResourceState, createLoadedResourceState, } from '../../../state/async_resource_builders'; -import { deleteHostIsolationExceptionItems, getHostIsolationExceptionItems } from '../service'; +import { + deleteHostIsolationExceptionItems, + getHostIsolationExceptionItems, + createHostIsolationExceptionItem, +} from '../service'; import { HostIsolationExceptionsPageState } from '../types'; import { getCurrentListPageDataState, getCurrentLocation, getItemToDelete } from './selector'; @@ -39,12 +45,50 @@ export const createHostIsolationExceptionsPageMiddleware = ( if (action.type === 'userChangedUrl' && isHostIsolationExceptionsPage(action.payload)) { loadHostIsolationExceptionsList(store, coreStart.http); } + + if (action.type === 'hostIsolationExceptionsCreateEntry') { + createHostIsolationException(store, coreStart.http); + } + if (action.type === 'hostIsolationExceptionsSubmitDelete') { deleteHostIsolationExceptionsItem(store, coreStart.http); } }; }; +async function createHostIsolationException( + store: ImmutableMiddlewareAPI, + http: HttpStart +) { + const { dispatch } = store; + const entry = transformNewItemOutput( + store.getState().form.entry as CreateExceptionListItemSchema + ); + dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: { + type: 'LoadingResourceState', + // @ts-expect-error-next-line will be fixed with when AsyncResourceState is refactored (#830) + previousState: entry, + }, + }); + try { + const response = await createHostIsolationExceptionItem({ + http, + exception: entry, + }); + dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: createLoadedResourceState(response), + }); + } catch (error) { + dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: createFailedResourceState(error.body ?? error), + }); + } +} + async function loadHostIsolationExceptionsList( store: ImmutableMiddlewareAPI, http: HttpStart diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.test.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.test.ts index 211b03f36d965..98b459fac41d3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.test.ts @@ -11,6 +11,7 @@ import { initialHostIsolationExceptionsPageState } from './builders'; import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; import { hostIsolationExceptionsPageReducer } from './reducer'; import { getCurrentLocation } from './selector'; +import { createEmptyHostIsolationException } from '../utils'; describe('Host Isolation Exceptions Reducer', () => { let initialState: HostIsolationExceptionsPageState; @@ -41,4 +42,13 @@ describe('Host Isolation Exceptions Reducer', () => { }); }); }); + it('should set an initial loading state when creating new entries', () => { + const entry = createEmptyHostIsolationException(); + const result = hostIsolationExceptionsPageReducer(initialState, { + type: 'hostIsolationExceptionsCreateEntry', + payload: entry, + }); + expect(result.form.status).toEqual({ type: 'UninitialisedResourceState' }); + expect(result.form.entry).toBe(entry); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts index 09182661a80b3..d97295598f445 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts @@ -38,6 +38,24 @@ export const hostIsolationExceptionsPageReducer: StateReducer = ( action ) => { switch (action.type) { + case 'hostIsolationExceptionsCreateEntry': { + return { + ...state, + form: { + entry: action.payload, + status: createUninitialisedResourceState(), + }, + }; + } + case 'hostIsolationExceptionsFormStateChanged': { + return { + ...state, + form: { + ...state.form, + status: action.payload, + }, + }; + } case 'hostIsolationExceptionsPageDataChanged': { return { ...state, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/types.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/types.ts index 443a86fefab83..1a74042fb652e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/types.ts @@ -6,6 +6,7 @@ */ import type { + CreateExceptionListItemSchema, ExceptionListItemSchema, FoundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; @@ -27,4 +28,8 @@ export interface HostIsolationExceptionsPageState { item?: ExceptionListItemSchema; status: AsyncResourceState; }; + form: { + entry?: CreateExceptionListItemSchema; + status: AsyncResourceState; + }; } diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/utils.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/utils.ts new file mode 100644 index 0000000000000..bfb1ac048e286 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/utils.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID } from '@kbn/securitysolution-list-constants'; +import ipaddr from 'ipaddr.js'; + +export function createEmptyHostIsolationException(): CreateExceptionListItemSchema { + return { + comments: [], + description: '', + entries: [ + { + field: 'destination.ip', + operator: 'included', + type: 'match', + value: '', + }, + ], + item_id: undefined, + list_id: ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID, + name: '', + namespace_type: 'agnostic', + os_types: ['windows', 'linux', 'macos'], + tags: ['policy:all'], + type: 'simple', + }; +} + +export function isValidIPv4OrCIDR(maybeIp: string): boolean { + try { + ipaddr.IPv4.parseCIDR(maybeIp); + return true; + } catch (e) { + return ipaddr.IPv4.isValid(maybeIp); + } +} diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx index d7c512794173c..eb53268a9fbd8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx @@ -7,7 +7,7 @@ import React, { memo } from 'react'; import styled, { css } from 'styled-components'; -import { EuiEmptyPrompt } from '@elastic/eui'; +import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; const EmptyPrompt = styled(EuiEmptyPrompt)` @@ -16,7 +16,7 @@ const EmptyPrompt = styled(EuiEmptyPrompt)` `} `; -export const HostIsolationExceptionsEmptyState = memo<{}>(() => { +export const HostIsolationExceptionsEmptyState = memo<{ onAdd: () => void }>(({ onAdd }) => { return ( (() => { defaultMessage="There are currently no host isolation exceptions" /> } + actions={ + + + + } /> ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx new file mode 100644 index 0000000000000..b06449de69d8c --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createEmptyHostIsolationException } from '../../utils'; +import { HostIsolationExceptionsForm } from './form'; +import React from 'react'; +import { + AppContextTestRender, + createAppRootMockRenderer, +} from '../../../../../common/mock/endpoint'; +import { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import userEvent from '@testing-library/user-event'; + +describe('When on the host isolation exceptions add entry form', () => { + let render: ( + exception: CreateExceptionListItemSchema + ) => ReturnType; + let renderResult: ReturnType; + const onChange = jest.fn(); + const onError = jest.fn(); + + beforeEach(() => { + onChange.mockReset(); + onError.mockReset(); + const mockedContext = createAppRootMockRenderer(); + render = (exception: CreateExceptionListItemSchema) => { + return mockedContext.render( + + ); + }; + }); + + describe('When creating a new exception', () => { + let newException: CreateExceptionListItemSchema; + beforeEach(() => { + newException = createEmptyHostIsolationException(); + renderResult = render(newException); + }); + it('should render the form with empty inputs', () => { + expect(renderResult.getByTestId('hostIsolationExceptions-form-name-input')).toHaveValue(''); + expect(renderResult.getByTestId('hostIsolationExceptions-form-ip-input')).toHaveValue(''); + expect( + renderResult.getByTestId('hostIsolationExceptions-form-description-input') + ).toHaveValue(''); + }); + it('should call onError with true when a wrong ip value is introduced', () => { + const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); + userEvent.type(ipInput, 'not an ip'); + expect(onError).toHaveBeenCalledWith(true); + }); + it('should call onError with false when a correct values are introduced', () => { + const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); + const nameInput = renderResult.getByTestId('hostIsolationExceptions-form-name-input'); + + userEvent.type(nameInput, 'test name'); + userEvent.type(ipInput, '10.0.0.1'); + + expect(onError).toHaveBeenLastCalledWith(false); + }); + it('should call onChange when a value is introduced in a field', () => { + const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); + userEvent.type(ipInput, '10.0.0.1'); + expect(onChange).toHaveBeenLastCalledWith({ + ...newException, + entries: [ + { field: 'destination.ip', operator: 'included', type: 'match', value: '10.0.0.1' }, + ], + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx new file mode 100644 index 0000000000000..84263f9d07c81 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -0,0 +1,206 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFieldText, + EuiForm, + EuiFormRow, + EuiHorizontalRule, + EuiSpacer, + EuiText, + EuiTextArea, + EuiTitle, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { isValidIPv4OrCIDR } from '../../utils'; +import { + DESCRIPTION_LABEL, + DESCRIPTION_PLACEHOLDER, + IP_ERROR, + IP_LABEL, + IP_PLACEHOLDER, + NAME_ERROR, + NAME_LABEL, + NAME_PLACEHOLDER, +} from './translations'; + +interface ExceptionIpEntry { + field: 'destination.ip'; + operator: 'included'; + type: 'match'; + value: ''; +} + +export const HostIsolationExceptionsForm: React.FC<{ + exception: CreateExceptionListItemSchema; + onError: (error: boolean) => void; + onChange: (exception: CreateExceptionListItemSchema) => void; +}> = memo(({ exception, onError, onChange }) => { + const [hasBeenInputNameVisited, setHasBeenInputNameVisited] = useState(false); + const [hasBeenInputIpVisited, setHasBeenInputIpVisited] = useState(false); + const [hasNameError, setHasNameError] = useState(true); + const [hasIpError, setHasIpError] = useState(true); + + useEffect(() => { + onError(hasNameError || hasIpError); + }, [hasNameError, hasIpError, onError]); + + const handleOnChangeName = useCallback( + (event: React.ChangeEvent) => { + const name = event.target.value; + if (!name.trim()) { + setHasNameError(true); + return; + } + setHasNameError(false); + onChange({ ...exception, name }); + }, + [exception, onChange] + ); + + const handleOnIpChange = useCallback( + (event: React.ChangeEvent) => { + const ip = event.target.value; + if (!isValidIPv4OrCIDR(ip)) { + setHasIpError(true); + return; + } + setHasIpError(false); + onChange({ + ...exception, + entries: [ + { + field: 'destination.ip', + operator: 'included', + type: 'match', + value: ip, + }, + ], + }); + }, + [exception, onChange] + ); + + const handleOnDescriptionChange = useCallback( + (event: React.ChangeEvent) => { + onChange({ ...exception, description: event.target.value }); + }, + [exception, onChange] + ); + + const nameInput = useMemo( + () => ( + + !hasBeenInputNameVisited && setHasBeenInputNameVisited(true)} + /> + + ), + [hasNameError, hasBeenInputNameVisited, exception.name, handleOnChangeName] + ); + + const ipInput = useMemo( + () => ( + + !hasBeenInputIpVisited && setHasBeenInputIpVisited(true)} + /> + + ), + [hasIpError, hasBeenInputIpVisited, exception.entries, handleOnIpChange] + ); + + const descriptionInput = useMemo( + () => ( + + + + ), + [exception.description, handleOnDescriptionChange] + ); + + return ( + + +

+ +

+
+ + + + + {nameInput} + {descriptionInput} + + + +

+ +

+
+ + + + + {ipInput} +
+ ); +}); + +HostIsolationExceptionsForm.displayName = 'HostIsolationExceptionsForm'; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx new file mode 100644 index 0000000000000..6cfc9f56beadf --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + AppContextTestRender, + createAppRootMockRenderer, +} from '../../../../../common/mock/endpoint'; +import userEvent from '@testing-library/user-event'; +import { HostIsolationExceptionsFormFlyout } from './form_flyout'; +import { act } from 'react-dom/test-utils'; +import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../../common/constants'; + +jest.mock('../../service.ts'); + +describe('When on the host isolation exceptions flyout form', () => { + let mockedContext: AppContextTestRender; + let render: () => ReturnType; + let renderResult: ReturnType; + let waitForAction: AppContextTestRender['middlewareSpy']['waitForAction']; + + // const createHostIsolationExceptionItemMock = createHostIsolationExceptionItem as jest.mock; + + beforeEach(() => { + mockedContext = createAppRootMockRenderer(); + render = () => { + return mockedContext.render(); + }; + waitForAction = mockedContext.middlewareSpy.waitForAction; + }); + + describe('When creating a new exception', () => { + describe('with invalid data', () => { + it('should show disabled buttons when the form first load', () => { + renderResult = render(); + expect(renderResult.getByTestId('add-exception-cancel-button')).not.toHaveAttribute( + 'disabled' + ); + expect(renderResult.getByTestId('add-exception-confirm-button')).toHaveAttribute( + 'disabled' + ); + }); + }); + describe('with valid data', () => { + beforeEach(() => { + renderResult = render(); + const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); + const nameInput = renderResult.getByTestId('hostIsolationExceptions-form-name-input'); + userEvent.type(nameInput, 'test name'); + userEvent.type(ipInput, '10.0.0.1'); + }); + it('should show enable buttons when the form is valid', () => { + expect(renderResult.getByTestId('add-exception-cancel-button')).not.toHaveAttribute( + 'disabled' + ); + expect(renderResult.getByTestId('add-exception-confirm-button')).not.toHaveAttribute( + 'disabled' + ); + }); + it('should submit the entry data when submit is pressed with valid data', async () => { + const confirmButton = renderResult.getByTestId('add-exception-confirm-button'); + expect(confirmButton).not.toHaveAttribute('disabled'); + const waiter = waitForAction('hostIsolationExceptionsCreateEntry'); + userEvent.click(confirmButton); + await waiter; + }); + it('should disable the submit button when an operation is in progress', () => { + act(() => { + mockedContext.store.dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: { + type: 'LoadingResourceState', + previousState: { type: 'UninitialisedResourceState' }, + }, + }); + }); + const confirmButton = renderResult.getByTestId('add-exception-confirm-button'); + expect(confirmButton).toHaveAttribute('disabled'); + }); + it('should show a toast and close the flyout when the operation is finished', () => { + mockedContext.history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=create`); + act(() => { + mockedContext.store.dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: { + type: 'LoadedResourceState', + previousState: { type: 'UninitialisedResourceState' }, + }, + }); + }); + expect(mockedContext.coreStart.notifications.toasts.addSuccess).toHaveBeenCalled(); + expect(mockedContext.history.location.search).toBe(''); + }); + it('should show an error toast operation fails and enable the submit button', () => { + act(() => { + mockedContext.store.dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: { + type: 'FailedResourceState', + previousState: { type: 'UninitialisedResourceState' }, + }, + }); + }); + expect(mockedContext.coreStart.notifications.toasts.addDanger).toHaveBeenCalled(); + const confirmButton = renderResult.getByTestId('add-exception-confirm-button'); + expect(confirmButton).not.toHaveAttribute('disabled'); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx new file mode 100644 index 0000000000000..5502a1b8ea2b1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -0,0 +1,180 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { useDispatch } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Loader } from '../../../../../common/components/loader'; +import { useToasts } from '../../../../../common/lib/kibana'; +import { + isFailedResourceState, + isLoadedResourceState, + isLoadingResourceState, +} from '../../../../state/async_resource_state'; +import { HostIsolationExceptionsPageAction } from '../../store/action'; +import { createEmptyHostIsolationException } from '../../utils'; +import { + useHostIsolationExceptionsNavigateCallback, + useHostIsolationExceptionsSelector, +} from '../hooks'; +import { HostIsolationExceptionsForm } from './form'; + +export const HostIsolationExceptionsFormFlyout: React.FC<{}> = memo(() => { + const dispatch = useDispatch>(); + const toasts = useToasts(); + + const creationInProgress = useHostIsolationExceptionsSelector((state) => + isLoadingResourceState(state.form.status) + ); + const creationSuccessful = useHostIsolationExceptionsSelector((state) => + isLoadedResourceState(state.form.status) + ); + const creationFailure = useHostIsolationExceptionsSelector((state) => + isFailedResourceState(state.form.status) + ); + + const navigateCallback = useHostIsolationExceptionsNavigateCallback(); + + const [formHasError, setFormHasError] = useState(true); + const [exception, setException] = useState(undefined); + + const onCancel = useCallback( + () => + navigateCallback({ + show: undefined, + id: undefined, + }), + [navigateCallback] + ); + + useEffect(() => { + setException(createEmptyHostIsolationException()); + }, []); + + useEffect(() => { + if (creationSuccessful) { + onCancel(); + dispatch({ + type: 'hostIsolationExceptionsFormStateChanged', + payload: { + type: 'UninitialisedResourceState', + }, + }); + toasts.addSuccess( + i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.creationSuccessToastTitle', + { + defaultMessage: '"{name}" has been added to the host isolation exceptions list.', + values: { name: exception?.name }, + } + ) + ); + } + }, [creationSuccessful, onCancel, dispatch, toasts, exception?.name]); + + useEffect(() => { + if (creationFailure) { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.creationFailureToastTitle', + { + defaultMessage: 'There was an error creating the exception', + } + ) + ); + } + }, [dispatch, toasts, creationFailure]); + + const handleOnCancel = useCallback(() => { + if (creationInProgress) return; + onCancel(); + }, [creationInProgress, onCancel]); + + const handleOnSubmit = useCallback(() => { + dispatch({ + type: 'hostIsolationExceptionsCreateEntry', + payload: exception, + }); + }, [dispatch, exception]); + + const confirmButtonMemo = useMemo( + () => ( + + + + ), + [formHasError, creationInProgress, handleOnSubmit] + ); + + return exception ? ( + + + +

+ +

+
+
+ + + + + + + + + + + + + {confirmButtonMemo} + + +
+ ) : ( + + ); +}); + +HostIsolationExceptionsFormFlyout.displayName = 'HostIsolationExceptionsFormFlyout'; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts new file mode 100644 index 0000000000000..df179c7a2221c --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const NAME_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.name.placeholder', + { + defaultMessage: 'New IP', + } +); + +export const NAME_LABEL = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.name.label', + { + defaultMessage: 'Name your host isolation exceptions', + } +); + +export const NAME_ERROR = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.name.error', + { + defaultMessage: "The name can't be empty", + } +); + +export const DESCRIPTION_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.description.placeholder', + { + defaultMessage: 'Describe your Host Isolation Exception', + } +); + +export const DESCRIPTION_LABEL = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.description.label', + { + defaultMessage: 'Description', + } +); + +export const IP_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.ip.placeholder', + { + defaultMessage: 'Ex 0.0.0.0/24', + } +); + +export const IP_LABEL = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.ip.label', + { + defaultMessage: 'Enter IP Address', + } +); + +export const IP_ERROR = i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.form.ip.error', + { + defaultMessage: 'The ip is invalid. Only IPv4 with optional CIDR is supported', + } +); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx index 53b8bc33c252f..ac472fdae4d7b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx @@ -5,16 +5,18 @@ * 2.0. */ -import React from 'react'; import { act } from '@testing-library/react'; -import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; -import { HostIsolationExceptionsList } from './host_isolation_exceptions_list'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; import { isFailedResourceState, isLoadedResourceState } from '../../../state'; import { getHostIsolationExceptionItems } from '../service'; -import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; +import { HostIsolationExceptionsList } from './host_isolation_exceptions_list'; jest.mock('../service'); + const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; describe('When on the host isolation exceptions page', () => { @@ -103,5 +105,17 @@ describe('When on the host isolation exceptions page', () => { ).toEqual(' Server is too far away'); }); }); + it('should show the create flyout when the add button is pressed', () => { + render(); + act(() => { + userEvent.click(renderResult.getByTestId('hostIsolationExceptionsListAddButton')); + }); + expect(renderResult.getByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy(); + }); + it('should show the create flyout when the show location is create', () => { + history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=create`); + render(); + expect(renderResult.getByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy(); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx index 53fb74d5bd8f7..cfb0121396e24 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx @@ -8,7 +8,7 @@ import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { i18n } from '@kbn/i18n'; import React, { Dispatch, useCallback } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiButton, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch } from 'react-redux'; import { ExceptionItem } from '../../../../common/components/exceptions/viewer/exception_item'; @@ -32,6 +32,7 @@ import { ArtifactEntryCard, ArtifactEntryCardProps } from '../../../components/a import { HostIsolationExceptionsEmptyState } from './components/empty'; import { HostIsolationExceptionsPageAction } from '../store/action'; import { HostIsolationExceptionDeleteModal } from './components/delete_modal'; +import { HostIsolationExceptionsFormFlyout } from './components/form_flyout'; type HostIsolationExceptionPaginatedContent = PaginatedContentProps< Immutable, @@ -54,6 +55,8 @@ export const HostIsolationExceptionsList = () => { const dispatch = useDispatch>(); const itemToDelete = useHostIsolationExceptionsSelector(getItemToDelete); + const showFlyout = !!location.show; + const navigateCallback = useHostIsolationExceptionsNavigateCallback(); const handleOnSearch = useCallback( @@ -92,6 +95,15 @@ export const HostIsolationExceptionsList = () => { [navigateCallback] ); + const handleAddButtonClick = useCallback( + () => + navigateCallback({ + show: 'create', + id: undefined, + }), + [navigateCallback] + ); + return ( { defaultMessage="Host Isolation Exceptions" /> } - actions={[]} + actions={ + + + + } > + {showFlyout && } + { pagination={pagination} contentClassName="host-isolation-exceptions-container" data-test-subj="hostIsolationExceptionsContent" - noItemsMessage={} + noItemsMessage={} /> ); From 7c5c566696fa3837b48d6147ae61dd97526f1a1d Mon Sep 17 00:00:00 2001 From: Orhan Toy Date: Mon, 11 Oct 2021 15:52:15 +0200 Subject: [PATCH 06/73] [Enterprise Search] Fix typo (#114462) Fixing a small typo (`recieve` -> `receive`) I noticed in comments. --- .../crawler_status_indicator/crawler_status_indicator.test.tsx | 2 +- .../applications/shared/flash_messages/handle_api_errors.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawler_status_indicator/crawler_status_indicator.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawler_status_indicator/crawler_status_indicator.test.tsx index 9d585789d8e50..c46c360934d0b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawler_status_indicator/crawler_status_indicator.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawler_status_indicator/crawler_status_indicator.test.tsx @@ -37,7 +37,7 @@ describe('CrawlerStatusIndicator', () => { describe('when status is not a valid status', () => { it('is disabled', () => { // this tests a codepath that should be impossible to reach, status should always be a CrawlerStatus - // but we use a switch statement and need to test the default case for this to recieve 100% coverage + // but we use a switch statement and need to test the default case for this to receive 100% coverage setMockValues({ ...MOCK_VALUES, mostRecentCrawlRequestStatus: null, diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts index 4fe8ad1cb851d..abaa67e06f606 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts @@ -14,7 +14,7 @@ import { IFlashMessage } from './types'; /** * The API errors we are handling can come from one of two ways: - * - When our http calls recieve a response containing an error code, such as a 404 or 500 + * - When our http calls receive a response containing an error code, such as a 404 or 500 * - Our own JS while handling a successful response * * In the first case, if it is a purposeful error (like a 404) we will receive an From 53109bdcd5fb00c8e4287facd03ed923362f8540 Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Mon, 11 Oct 2021 15:20:39 +0100 Subject: [PATCH 07/73] Detection Rule Exception List telemetry (#113239) * Add telemetry for detection rule exception lists to improve UX. * Add length for debugging. * Fix type. * Clean up exception list telemetry document. * Dynamically set kibana index (just in case). * Update task title. * Rename version to rule_version. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/telemetry/constants.ts | 6 +- .../server/lib/telemetry/filters.ts | 5 +- .../server/lib/telemetry/helpers.test.ts | 80 +++++++--- .../server/lib/telemetry/helpers.ts | 48 ++++-- .../server/lib/telemetry/mocks.ts | 11 +- .../server/lib/telemetry/receiver.ts | 68 +++++++- .../server/lib/telemetry/sender.ts | 10 +- .../telemetry/tasks/detection_rule.test.ts | 127 +++++++++++++++ .../lib/telemetry/tasks/detection_rule.ts | 149 ++++++++++++++++++ .../server/lib/telemetry/tasks/endpoint.ts | 4 +- .../server/lib/telemetry/tasks/index.ts | 1 + .../server/lib/telemetry/types.ts | 39 ++++- .../security_solution/server/plugin.ts | 8 +- 13 files changed, 499 insertions(+), 57 deletions(-) create mode 100644 x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts index 771e3e059c336..91f83d5e7cb37 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -7,12 +7,14 @@ export const TELEMETRY_MAX_BUFFER_SIZE = 100; -export const TELEMETRY_CHANNEL_LISTS = 'security-lists'; +export const TELEMETRY_CHANNEL_LISTS = 'security-lists-v2'; export const TELEMETRY_CHANNEL_ENDPOINT_META = 'endpoint-metadata'; -export const LIST_TRUSTED_APPLICATION = 'trusted_application'; +export const LIST_DETECTION_RULE_EXCEPTION = 'detection_rule_exception'; export const LIST_ENDPOINT_EXCEPTION = 'endpoint_exception'; export const LIST_ENDPOINT_EVENT_FILTER = 'endpoint_event_filter'; + +export const LIST_TRUSTED_APPLICATION = 'trusted_application'; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts index 61172fac511f7..a29f195ed5ecc 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts @@ -129,13 +129,12 @@ export const allowlistEventFields: AllowlistFields = { export const exceptionListEventFields: AllowlistFields = { created_at: true, - description: true, effectScope: true, entries: true, id: true, name: true, - os: true, os_types: true, + rule_version: true, }; /** @@ -143,7 +142,7 @@ export const exceptionListEventFields: AllowlistFields = { * * @param allowlist * @param event - * @returns + * @returns TelemetryEvent with explicitly required fields */ export function copyAllowlistedFields( allowlist: AllowlistFields, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts index 647219e8c5585..528082d8cb5b1 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts @@ -8,13 +8,14 @@ import moment from 'moment'; import { createMockPackagePolicy } from './mocks'; import { + LIST_DETECTION_RULE_EXCEPTION, LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER, LIST_TRUSTED_APPLICATION, } from './constants'; import { getPreviousDiagTaskTimestamp, - getPreviousEpMetaTaskTimestamp, + getPreviousDailyTaskTimestamp, batchTelemetryRecords, isPackagePolicyList, templateExceptionList, @@ -53,7 +54,7 @@ describe('test endpoint meta telemetry scheduled task timing helper', () => { test('test -24 hours is returned when there is no previous task run', async () => { const executeTo = moment().utc().toISOString(); const executeFrom = undefined; - const newExecuteFrom = getPreviousEpMetaTaskTimestamp(executeTo, executeFrom); + const newExecuteFrom = getPreviousDailyTaskTimestamp(executeTo, executeFrom); expect(newExecuteFrom).toEqual(moment(executeTo).subtract(24, 'hours').toISOString()); }); @@ -61,7 +62,7 @@ describe('test endpoint meta telemetry scheduled task timing helper', () => { test('test -24 hours is returned when there was a previous task run', async () => { const executeTo = moment().utc().toISOString(); const executeFrom = moment(executeTo).subtract(24, 'hours').toISOString(); - const newExecuteFrom = getPreviousEpMetaTaskTimestamp(executeTo, executeFrom); + const newExecuteFrom = getPreviousDailyTaskTimestamp(executeTo, executeFrom); expect(newExecuteFrom).toEqual(executeFrom); }); @@ -71,7 +72,7 @@ describe('test endpoint meta telemetry scheduled task timing helper', () => { test('test 24 hours is returned when previous task run took longer than 24 hours', async () => { const executeTo = moment().utc().toISOString(); const executeFrom = moment(executeTo).subtract(72, 'hours').toISOString(); // down 3 days - const newExecuteFrom = getPreviousEpMetaTaskTimestamp(executeTo, executeFrom); + const newExecuteFrom = getPreviousDailyTaskTimestamp(executeTo, executeFrom); expect(newExecuteFrom).toEqual(moment(executeTo).subtract(24, 'hours').toISOString()); }); @@ -134,61 +135,88 @@ describe('test package policy type guard', () => { }); describe('list telemetry schema', () => { + test('detection rules document is correctly formed', () => { + const data = [{ id: 'test_1' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_DETECTION_RULE_EXCEPTION); + + expect(templatedItems[0]?.detection_rule).not.toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); + }); + + test('detection rules document is correctly formed with multiple entries', () => { + const data = [{ id: 'test_2' }, { id: 'test_2' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_DETECTION_RULE_EXCEPTION); + + expect(templatedItems[0]?.detection_rule).not.toBeUndefined(); + expect(templatedItems[1]?.detection_rule).not.toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); + }); + test('trusted apps document is correctly formed', () => { const data = [{ id: 'test_1' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_TRUSTED_APPLICATION); - expect(templatedItems[0]?.trusted_application.length).toEqual(1); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).not.toBeUndefined(); }); test('trusted apps document is correctly formed with multiple entries', () => { const data = [{ id: 'test_2' }, { id: 'test_2' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_TRUSTED_APPLICATION); - expect(templatedItems[0]?.trusted_application.length).toEqual(1); - expect(templatedItems[1]?.trusted_application.length).toEqual(1); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).not.toBeUndefined(); + expect(templatedItems[1]?.trusted_application).not.toBeUndefined(); }); test('endpoint exception document is correctly formed', () => { const data = [{ id: 'test_3' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EXCEPTION); - expect(templatedItems[0]?.trusted_application.length).toEqual(0); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).not.toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); }); test('endpoint exception document is correctly formed with multiple entries', () => { const data = [{ id: 'test_4' }, { id: 'test_4' }, { id: 'test_4' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EXCEPTION); - expect(templatedItems[0]?.trusted_application.length).toEqual(0); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); - expect(templatedItems[1]?.endpoint_exception.length).toEqual(1); - expect(templatedItems[2]?.endpoint_exception.length).toEqual(1); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).not.toBeUndefined(); + expect(templatedItems[1]?.endpoint_exception).not.toBeUndefined(); + expect(templatedItems[2]?.endpoint_exception).not.toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); }); test('endpoint event filters document is correctly formed', () => { const data = [{ id: 'test_5' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EVENT_FILTER); - expect(templatedItems[0]?.trusted_application.length).toEqual(0); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(1); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).not.toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); }); test('endpoint event filters document is correctly formed with multiple entries', () => { const data = [{ id: 'test_6' }, { id: 'test_6' }] as ExceptionListItem[]; const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EVENT_FILTER); - expect(templatedItems[0]?.trusted_application.length).toEqual(0); - expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); - expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(1); - expect(templatedItems[1]?.endpoint_event_filter.length).toEqual(1); + expect(templatedItems[0]?.detection_rule).toBeUndefined(); + expect(templatedItems[0]?.endpoint_event_filter).not.toBeUndefined(); + expect(templatedItems[1]?.endpoint_event_filter).not.toBeUndefined(); + expect(templatedItems[0]?.endpoint_exception).toBeUndefined(); + expect(templatedItems[0]?.trusted_application).toBeUndefined(); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts index a9eaef3ce6edc..e72b0ba7d16fe 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts @@ -11,6 +11,7 @@ import { PackagePolicy } from '../../../../fleet/common/types/models/package_pol import { copyAllowlistedFields, exceptionListEventFields } from './filters'; import { ExceptionListItem, ListTemplate, TelemetryEvent } from './types'; import { + LIST_DETECTION_RULE_EXCEPTION, LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER, LIST_TRUSTED_APPLICATION, @@ -46,7 +47,7 @@ export const getPreviousDiagTaskTimestamp = ( * @param lastExecutionTimestamp * @returns the timestamp to search from */ -export const getPreviousEpMetaTaskTimestamp = ( +export const getPreviousDailyTaskTimestamp = ( executeTo: string, lastExecutionTimestamp?: string ) => { @@ -97,18 +98,16 @@ export function isPackagePolicyList( * Maps trusted application to shared telemetry object * * @param exceptionListItem - * @returns collection of endpoint exceptions + * @returns collection of trusted applications */ export const trustedApplicationToTelemetryEntry = (trustedApplication: TrustedApp) => { return { id: trustedApplication.id, - version: trustedApplication.version || '', name: trustedApplication.name, - description: trustedApplication.description, created_at: trustedApplication.created_at, updated_at: trustedApplication.updated_at, entries: trustedApplication.entries, - os: trustedApplication.os, + os_types: [trustedApplication.os], } as ExceptionListItem; }; @@ -121,9 +120,29 @@ export const trustedApplicationToTelemetryEntry = (trustedApplication: TrustedAp export const exceptionListItemToTelemetryEntry = (exceptionListItem: ExceptionListItemSchema) => { return { id: exceptionListItem.id, - version: exceptionListItem._version || '', name: exceptionListItem.name, - description: exceptionListItem.description, + created_at: exceptionListItem.created_at, + updated_at: exceptionListItem.updated_at, + entries: exceptionListItem.entries, + os_types: exceptionListItem.os_types, + } as ExceptionListItem; +}; + +/** + * Maps detection rule exception list items to shared telemetry object + * + * @param exceptionListItem + * @param ruleVersion + * @returns collection of detection rule exceptions + */ +export const ruleExceptionListItemToTelemetryEvent = ( + exceptionListItem: ExceptionListItemSchema, + ruleVersion: number +) => { + return { + id: exceptionListItem.item_id, + name: exceptionListItem.description, + rule_version: ruleVersion, created_at: exceptionListItem.created_at, updated_at: exceptionListItem.updated_at, entries: exceptionListItem.entries, @@ -141,9 +160,7 @@ export const exceptionListItemToTelemetryEntry = (exceptionListItem: ExceptionLi export const templateExceptionList = (listData: ExceptionListItem[], listType: string) => { return listData.map((item) => { const template: ListTemplate = { - trusted_application: [], - endpoint_exception: [], - endpoint_event_filter: [], + '@timestamp': new Date().getTime(), }; // cast exception list type to a TelemetryEvent for allowlist filtering @@ -152,18 +169,23 @@ export const templateExceptionList = (listData: ExceptionListItem[], listType: s item as unknown as TelemetryEvent ); + if (listType === LIST_DETECTION_RULE_EXCEPTION) { + template.detection_rule = filteredListItem; + return template; + } + if (listType === LIST_TRUSTED_APPLICATION) { - template.trusted_application.push(filteredListItem); + template.trusted_application = filteredListItem; return template; } if (listType === LIST_ENDPOINT_EXCEPTION) { - template.endpoint_exception.push(filteredListItem); + template.endpoint_exception = filteredListItem; return template; } if (listType === LIST_ENDPOINT_EVENT_FILTER) { - template.endpoint_event_filter.push(filteredListItem); + template.endpoint_event_filter = filteredListItem; return template; } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts b/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts index 20a71657b2ffe..9168683141e48 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts @@ -8,7 +8,7 @@ // eslint-disable-next-line max-classes-per-file import { TelemetryEventsSender } from './sender'; import { TelemetryReceiver } from './receiver'; -import { DiagnosticTask, EndpointTask, ExceptionListsTask } from './tasks'; +import { DiagnosticTask, EndpointTask, ExceptionListsTask, DetectionRulesTask } from './tasks'; import { PackagePolicy } from '../../../../fleet/common/types/models/package_policy'; /** @@ -40,6 +40,8 @@ export const createMockTelemetryReceiver = (): jest.Mocked => fetchEndpointMetrics: jest.fn(), fetchEndpointPolicyResponses: jest.fn(), fetchTrustedApplications: jest.fn(), + fetchDetectionRules: jest.fn(), + fetchDetectionExceptionList: jest.fn(), } as unknown as jest.Mocked; }; @@ -79,3 +81,10 @@ export class MockTelemetryEndpointTask extends EndpointTask { export class MockExceptionListsTask extends ExceptionListsTask { public runTask = jest.fn(); } + +/** + * Creates a mocked Telemetry detection rules lists Task + */ +export class MockDetectionRuleListsTask extends DetectionRulesTask { + public runTask = jest.fn(); +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts index 038b7687784f4..94aa6c867304f 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -17,8 +17,18 @@ import { AgentService, AgentPolicyServiceInterface } from '../../../../fleet/ser import { ExceptionListClient } from '../../../../lists/server'; import { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; import { TELEMETRY_MAX_BUFFER_SIZE } from './constants'; -import { exceptionListItemToTelemetryEntry, trustedApplicationToTelemetryEntry } from './helpers'; -import { TelemetryEvent, ESLicense, ESClusterInfo, GetEndpointListResponse } from './types'; +import { + exceptionListItemToTelemetryEntry, + trustedApplicationToTelemetryEntry, + ruleExceptionListItemToTelemetryEvent, +} from './helpers'; +import { + TelemetryEvent, + ESLicense, + ESClusterInfo, + GetEndpointListResponse, + RuleSearchResult, +} from './types'; export class TelemetryReceiver { private readonly logger: Logger; @@ -27,6 +37,7 @@ export class TelemetryReceiver { private esClient?: ElasticsearchClient; private exceptionListClient?: ExceptionListClient; private soClient?: SavedObjectsClientContract; + private kibanaIndex?: string; private readonly max_records = 10_000; constructor(logger: Logger) { @@ -35,9 +46,11 @@ export class TelemetryReceiver { public async start( core?: CoreStart, + kibanaIndex?: string, endpointContextService?: EndpointAppContextService, exceptionListClient?: ExceptionListClient ) { + this.kibanaIndex = kibanaIndex; this.agentService = endpointContextService?.getAgentService(); this.agentPolicyService = endpointContextService?.getAgentPolicyService(); this.esClient = core?.elasticsearch.client.asInternalUser; @@ -240,6 +253,57 @@ export class TelemetryReceiver { }; } + public async fetchDetectionRules() { + if (this.esClient === undefined || this.esClient === null) { + throw Error('elasticsearch client is unavailable: cannot retrieve diagnostic alerts'); + } + + const query: SearchRequest = { + expand_wildcards: 'open,hidden', + index: `${this.kibanaIndex}*`, + ignore_unavailable: true, + size: this.max_records, + body: { + query: { + bool: { + filter: [ + { term: { 'alert.alertTypeId': 'siem.signals' } }, + { term: { 'alert.params.immutable': true } }, + ], + }, + }, + }, + }; + + return this.esClient.search(query); + } + + public async fetchDetectionExceptionList(listId: string, ruleVersion: number) { + if (this?.exceptionListClient === undefined || this?.exceptionListClient === null) { + throw Error('exception list client is unavailable: could not retrieve trusted applications'); + } + + // Ensure list is created if it does not exist + await this.exceptionListClient.createTrustedAppsList(); + + const results = await this.exceptionListClient?.findExceptionListsItem({ + listId: [listId], + filter: [], + perPage: this.max_records, + page: 1, + sortField: 'exception-list.created_at', + sortOrder: 'desc', + namespaceType: ['single'], + }); + + return { + data: results?.data.map((r) => ruleExceptionListItemToTelemetryEvent(r, ruleVersion)) ?? [], + total: results?.total ?? 0, + page: results?.page ?? 1, + per_page: results?.per_page ?? this.max_records, + }; + } + public async fetchClusterInfo(): Promise { if (this.esClient === undefined || this.esClient === null) { throw Error('elasticsearch client is unavailable: cannot retrieve cluster infomation'); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 0037aaa28fee3..b0792ed7b4610 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -18,7 +18,7 @@ import { } from '../../../../task_manager/server'; import { TelemetryReceiver } from './receiver'; import { allowlistEventFields, copyAllowlistedFields } from './filters'; -import { DiagnosticTask, EndpointTask, ExceptionListsTask } from './tasks'; +import { DiagnosticTask, EndpointTask, ExceptionListsTask, DetectionRulesTask } from './tasks'; import { createUsageCounterLabel } from './helpers'; import { TelemetryEvent } from './types'; import { TELEMETRY_MAX_BUFFER_SIZE } from './constants'; @@ -42,6 +42,7 @@ export class TelemetryEventsSender { private diagnosticTask?: DiagnosticTask; private endpointTask?: EndpointTask; private exceptionListsTask?: ExceptionListsTask; + private detectionRulesTask?: DetectionRulesTask; constructor(logger: Logger) { this.logger = logger.get('telemetry_events'); @@ -59,6 +60,12 @@ export class TelemetryEventsSender { if (taskManager) { this.diagnosticTask = new DiagnosticTask(this.logger, taskManager, this, telemetryReceiver); this.endpointTask = new EndpointTask(this.logger, taskManager, this, telemetryReceiver); + this.detectionRulesTask = new DetectionRulesTask( + this.logger, + taskManager, + this, + telemetryReceiver + ); this.exceptionListsTask = new ExceptionListsTask( this.logger, taskManager, @@ -80,6 +87,7 @@ export class TelemetryEventsSender { this.logger.debug(`starting security telemetry tasks`); this.diagnosticTask.start(taskManager); this.endpointTask.start(taskManager); + this.detectionRulesTask?.start(taskManager); this.exceptionListsTask?.start(taskManager); } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.test.ts new file mode 100644 index 0000000000000..0a05afb8a6535 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.test.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from 'src/core/server/mocks'; +import { taskManagerMock } from '../../../../../task_manager/server/mocks'; +import { TaskStatus } from '../../../../../task_manager/server'; +import { + TelemetryDetectionRulesTask, + TelemetryDetectionRuleListsTaskConstants, +} from './detection_rule'; +import { + createMockTelemetryEventsSender, + MockDetectionRuleListsTask, + createMockTelemetryReceiver, +} from '../mocks'; + +describe('test detection rule exception lists telemetry', () => { + let logger: ReturnType; + + beforeEach(() => { + logger = loggingSystemMock.createLogger(); + }); + + describe('basic telemetry sanity checks', () => { + test('detection rule lists task can register', () => { + const telemetryDiagTask = new TelemetryDetectionRulesTask( + logger, + taskManagerMock.createSetup(), + createMockTelemetryEventsSender(true), + createMockTelemetryReceiver() + ); + + expect(telemetryDiagTask).toBeInstanceOf(TelemetryDetectionRulesTask); + }); + }); + + test('detection rule task should be registered', () => { + const mockTaskManager = taskManagerMock.createSetup(); + new TelemetryDetectionRulesTask( + logger, + mockTaskManager, + createMockTelemetryEventsSender(true), + createMockTelemetryReceiver() + ); + + expect(mockTaskManager.registerTaskDefinitions).toHaveBeenCalled(); + }); + + test('detection rule task should be scheduled', async () => { + const mockTaskManagerSetup = taskManagerMock.createSetup(); + const telemetryDiagTask = new TelemetryDetectionRulesTask( + logger, + mockTaskManagerSetup, + createMockTelemetryEventsSender(true), + createMockTelemetryReceiver() + ); + + const mockTaskManagerStart = taskManagerMock.createStart(); + await telemetryDiagTask.start(mockTaskManagerStart); + expect(mockTaskManagerStart.ensureScheduled).toHaveBeenCalled(); + }); + + test('detection rule task should run', async () => { + const mockContext = createMockTelemetryEventsSender(true); + const mockTaskManager = taskManagerMock.createSetup(); + const mockReceiver = createMockTelemetryReceiver(); + const telemetryDiagTask = new MockDetectionRuleListsTask( + logger, + mockTaskManager, + mockContext, + mockReceiver + ); + + const mockTaskInstance = { + id: TelemetryDetectionRuleListsTaskConstants.TYPE, + runAt: new Date(), + attempts: 0, + ownerId: '', + status: TaskStatus.Running, + startedAt: new Date(), + scheduledAt: new Date(), + retryAt: new Date(), + params: {}, + state: {}, + taskType: TelemetryDetectionRuleListsTaskConstants.TYPE, + }; + const createTaskRunner = + mockTaskManager.registerTaskDefinitions.mock.calls[0][0][ + TelemetryDetectionRuleListsTaskConstants.TYPE + ].createTaskRunner; + const taskRunner = createTaskRunner({ taskInstance: mockTaskInstance }); + await taskRunner.run(); + expect(telemetryDiagTask.runTask).toHaveBeenCalled(); + }); + + test('detection rule task should not query elastic if telemetry is not opted in', async () => { + const mockSender = createMockTelemetryEventsSender(false); + const mockTaskManager = taskManagerMock.createSetup(); + const mockReceiver = createMockTelemetryReceiver(); + new MockDetectionRuleListsTask(logger, mockTaskManager, mockSender, mockReceiver); + + const mockTaskInstance = { + id: TelemetryDetectionRuleListsTaskConstants.TYPE, + runAt: new Date(), + attempts: 0, + ownerId: '', + status: TaskStatus.Running, + startedAt: new Date(), + scheduledAt: new Date(), + retryAt: new Date(), + params: {}, + state: {}, + taskType: TelemetryDetectionRuleListsTaskConstants.TYPE, + }; + const createTaskRunner = + mockTaskManager.registerTaskDefinitions.mock.calls[0][0][ + TelemetryDetectionRuleListsTaskConstants.TYPE + ].createTaskRunner; + const taskRunner = createTaskRunner({ taskInstance: mockTaskInstance }); + await taskRunner.run(); + expect(mockReceiver.fetchDiagnosticAlerts).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts new file mode 100644 index 0000000000000..a362be187921d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; +import { Logger } from 'src/core/server'; +import { + ConcreteTaskInstance, + TaskManagerSetupContract, + TaskManagerStartContract, +} from '../../../../../task_manager/server'; +import { LIST_DETECTION_RULE_EXCEPTION, TELEMETRY_CHANNEL_LISTS } from '../constants'; +import { batchTelemetryRecords, templateExceptionList } from '../helpers'; +import { TelemetryEventsSender } from '../sender'; +import { TelemetryReceiver } from '../receiver'; +import { ExceptionListItem, RuleSearchResult } from '../types'; + +export const TelemetryDetectionRuleListsTaskConstants = { + TIMEOUT: '10m', + TYPE: 'security:telemetry-detection-rules', + INTERVAL: '24h', + VERSION: '1.0.0', +}; + +const MAX_TELEMETRY_BATCH = 1_000; + +export class TelemetryDetectionRulesTask { + private readonly logger: Logger; + private readonly sender: TelemetryEventsSender; + private readonly receiver: TelemetryReceiver; + + constructor( + logger: Logger, + taskManager: TaskManagerSetupContract, + sender: TelemetryEventsSender, + receiver: TelemetryReceiver + ) { + this.logger = logger; + this.sender = sender; + this.receiver = receiver; + + taskManager.registerTaskDefinitions({ + [TelemetryDetectionRuleListsTaskConstants.TYPE]: { + title: 'Security Solution Detection Rule Lists Telemetry', + timeout: TelemetryDetectionRuleListsTaskConstants.TIMEOUT, + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + const { state } = taskInstance; + + return { + run: async () => { + const taskExecutionTime = moment().utc().toISOString(); + const hits = await this.runTask(taskInstance.id); + + return { + state: { + lastExecutionTimestamp: taskExecutionTime, + runs: (state.runs || 0) + 1, + hits, + }, + }; + }, + cancel: async () => {}, + }; + }, + }, + }); + } + + public start = async (taskManager: TaskManagerStartContract) => { + try { + await taskManager.ensureScheduled({ + id: this.getTaskId(), + taskType: TelemetryDetectionRuleListsTaskConstants.TYPE, + scope: ['securitySolution'], + schedule: { + interval: TelemetryDetectionRuleListsTaskConstants.INTERVAL, + }, + state: { runs: 0 }, + params: { version: TelemetryDetectionRuleListsTaskConstants.VERSION }, + }); + } catch (e) { + this.logger.error(`Error scheduling task, received ${e.message}`); + } + }; + + private getTaskId = (): string => { + return `${TelemetryDetectionRuleListsTaskConstants.TYPE}:${TelemetryDetectionRuleListsTaskConstants.VERSION}`; + }; + + public runTask = async (taskId: string) => { + if (taskId !== this.getTaskId()) { + return 0; + } + + const isOptedIn = await this.sender.isTelemetryOptedIn(); + if (!isOptedIn) { + return 0; + } + + // Lists Telemetry: Detection Rules + + const { body: prebuiltRules } = await this.receiver.fetchDetectionRules(); + + const cacheArray = prebuiltRules.hits.hits.reduce((cache, searchHit) => { + const rule = searchHit._source as RuleSearchResult; + const ruleId = rule.alert.params.ruleId; + + const shouldNotProcess = + rule === null || + rule === undefined || + ruleId === null || + ruleId === undefined || + searchHit._source?.alert.params.exceptionsList.length === 0; + + if (shouldNotProcess) { + return cache; + } + + cache.push(rule); + return cache; + }, [] as RuleSearchResult[]); + + const detectionRuleExceptions = [] as ExceptionListItem[]; + for (const item of cacheArray) { + const ruleVersion = item.alert.params.version; + + for (const ex of item.alert.params.exceptionsList) { + const listItem = await this.receiver.fetchDetectionExceptionList(ex.list_id, ruleVersion); + for (const exceptionItem of listItem.data) { + detectionRuleExceptions.push(exceptionItem); + } + } + } + + const detectionRuleExceptionsJson = templateExceptionList( + detectionRuleExceptions, + LIST_DETECTION_RULE_EXCEPTION + ); + + batchTelemetryRecords(detectionRuleExceptionsJson, MAX_TELEMETRY_BATCH).forEach((batch) => { + this.sender.sendOnDemand(TELEMETRY_CHANNEL_LISTS, batch); + }); + + return detectionRuleExceptions.length; + }; +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts index 0c066deea17d9..c6bf4b06e70f0 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts @@ -14,7 +14,7 @@ import { } from '../../../../../task_manager/server'; import { batchTelemetryRecords, - getPreviousEpMetaTaskTimestamp, + getPreviousDailyTaskTimestamp, isPackagePolicyList, } from '../helpers'; import { TelemetryEventsSender } from '../sender'; @@ -76,7 +76,7 @@ export class TelemetryEndpointTask { return { run: async () => { const taskExecutionTime = moment().utc().toISOString(); - const lastExecutionTimestamp = getPreviousEpMetaTaskTimestamp( + const lastExecutionTimestamp = getPreviousDailyTaskTimestamp( taskExecutionTime, taskInstance.state?.lastExecutionTimestamp ); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts index e090252b88d8f..a850f848567cb 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts @@ -8,3 +8,4 @@ export { TelemetryDiagTask as DiagnosticTask } from './diagnostic'; export { TelemetryEndpointTask as EndpointTask } from './endpoint'; export { TelemetryExceptionListsTask as ExceptionListsTask } from './security_lists'; +export { TelemetryDetectionRulesTask as DetectionRulesTask } from './detection_rule'; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts index abcad26ed000c..6aaf6f4371475 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts @@ -217,18 +217,45 @@ export interface GetEndpointListResponse { export interface ExceptionListItem { id: string; - version: string; + rule_version?: number; name: string; - description: string; created_at: string; updated_at: string; entries: object; - os: string; os_types: object; } export interface ListTemplate { - trusted_application: TelemetryEvent[]; - endpoint_exception: TelemetryEvent[]; - endpoint_event_filter: TelemetryEvent[]; + '@timestamp': number; + detection_rule?: TelemetryEvent; + endpoint_exception?: TelemetryEvent; + endpoint_event_filter?: TelemetryEvent; + trusted_application?: TelemetryEvent; +} + +// Detection Rule types + +interface ExceptionListEntry { + id: string; + list_id: string; + type: string; + namespace_type: string; +} + +interface DetectionRuleParms { + ruleId: string; + version: number; + type: string; + exceptionsList: ExceptionListEntry[]; +} + +export interface RuleSearchResult { + alert: { + name: string; + enabled: boolean; + tags: string[]; + createdAt: string; + updatedAt: string; + params: DetectionRuleParms; + }; } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index bffcc823d047e..f0a91f8b06c00 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -459,7 +459,13 @@ export class Plugin implements IPlugin Date: Mon, 11 Oct 2021 17:30:18 +0200 Subject: [PATCH 08/73] [bfetch] Pass `compress` flag in query instead of headers (#113929) --- src/plugins/bfetch/common/util/index.ts | 1 + .../bfetch/common/util/query_params.ts | 12 +++ .../public/streaming/fetch_streaming.ts | 12 +-- src/plugins/bfetch/server/index.ts | 1 - src/plugins/bfetch/server/mocks.ts | 1 - src/plugins/bfetch/server/plugin.ts | 78 +------------------ .../bfetch/server/streaming/create_stream.ts | 8 +- src/plugins/bfetch/server/types.ts | 27 ------- test/api_integration/apis/search/bsearch.ts | 66 +++++++--------- 9 files changed, 56 insertions(+), 150 deletions(-) create mode 100644 src/plugins/bfetch/common/util/query_params.ts delete mode 100644 src/plugins/bfetch/server/types.ts diff --git a/src/plugins/bfetch/common/util/index.ts b/src/plugins/bfetch/common/util/index.ts index 1651d24d96b14..f20d30eb3cdf0 100644 --- a/src/plugins/bfetch/common/util/index.ts +++ b/src/plugins/bfetch/common/util/index.ts @@ -8,3 +8,4 @@ export * from './normalize_error'; export * from './remove_leading_slash'; +export * from './query_params'; diff --git a/src/plugins/bfetch/common/util/query_params.ts b/src/plugins/bfetch/common/util/query_params.ts new file mode 100644 index 0000000000000..ed65699fbcafc --- /dev/null +++ b/src/plugins/bfetch/common/util/query_params.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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const appendQueryParam = (url: string, key: string, value: string): string => { + const separator = url.includes('?') ? '&' : '?'; + return `${url}${separator}${key}=${value}`; +}; diff --git a/src/plugins/bfetch/public/streaming/fetch_streaming.ts b/src/plugins/bfetch/public/streaming/fetch_streaming.ts index a94c8d3980cba..77e5acffc1af3 100644 --- a/src/plugins/bfetch/public/streaming/fetch_streaming.ts +++ b/src/plugins/bfetch/public/streaming/fetch_streaming.ts @@ -10,6 +10,7 @@ import { map, share } from 'rxjs/operators'; import { inflateResponse } from '.'; import { fromStreamingXhr } from './from_streaming_xhr'; import { split } from './split'; +import { appendQueryParam } from '../../common'; export interface FetchStreamingParams { url: string; @@ -34,16 +35,15 @@ export function fetchStreaming({ }: FetchStreamingParams) { const xhr = new window.XMLHttpRequest(); - // Begin the request - xhr.open(method, url); - xhr.withCredentials = true; - const isCompressionDisabled = getIsCompressionDisabled(); - if (!isCompressionDisabled) { - headers['X-Chunk-Encoding'] = 'deflate'; + url = appendQueryParam(url, 'compress', 'true'); } + // Begin the request + xhr.open(method, url); + xhr.withCredentials = true; + // Set the HTTP headers Object.entries(headers).forEach(([k, v]) => xhr.setRequestHeader(k, v)); diff --git a/src/plugins/bfetch/server/index.ts b/src/plugins/bfetch/server/index.ts index c533b2ad7a3df..f4c41d10e42cb 100644 --- a/src/plugins/bfetch/server/index.ts +++ b/src/plugins/bfetch/server/index.ts @@ -10,7 +10,6 @@ import { PluginInitializerContext } from '../../../core/server'; import { BfetchServerPlugin } from './plugin'; export { BfetchServerSetup, BfetchServerStart, BatchProcessingRouteParams } from './plugin'; -export { StreamingRequestHandler } from './types'; export function plugin(initializerContext: PluginInitializerContext) { return new BfetchServerPlugin(initializerContext); diff --git a/src/plugins/bfetch/server/mocks.ts b/src/plugins/bfetch/server/mocks.ts index bbb596bf8d5ff..dfa365d9e70b2 100644 --- a/src/plugins/bfetch/server/mocks.ts +++ b/src/plugins/bfetch/server/mocks.ts @@ -17,7 +17,6 @@ const createSetupContract = (): Setup => { const setupContract: Setup = { addBatchProcessingRoute: jest.fn(), addStreamingResponseRoute: jest.fn(), - createStreamingRequestHandler: jest.fn(), }; return setupContract; }; diff --git a/src/plugins/bfetch/server/plugin.ts b/src/plugins/bfetch/server/plugin.ts index 7b60be9a8fc75..f7127445f96c5 100644 --- a/src/plugins/bfetch/server/plugin.ts +++ b/src/plugins/bfetch/server/plugin.ts @@ -13,9 +13,6 @@ import type { Plugin, Logger, KibanaRequest, - RouteMethod, - RequestHandler, - RequestHandlerContext, StartServicesAccessor, } from 'src/core/server'; import { schema } from '@kbn/config-schema'; @@ -28,7 +25,6 @@ import { removeLeadingSlash, normalizeError, } from '../common'; -import { StreamingRequestHandler } from './types'; import { createStream } from './streaming'; import { getUiSettings } from './ui_settings'; @@ -52,44 +48,6 @@ export interface BfetchServerSetup { path: string, params: (request: KibanaRequest) => StreamingResponseHandler ) => void; - /** - * Create a streaming request handler to be able to use an Observable to return chunked content to the client. - * This is meant to be used with the `fetchStreaming` API of the `bfetch` client-side plugin. - * - * @example - * ```ts - * setup({ http }: CoreStart, { bfetch }: SetupDeps) { - * const router = http.createRouter(); - * router.post( - * { - * path: '/api/my-plugin/stream-endpoint, - * validate: { - * body: schema.object({ - * term: schema.string(), - * }), - * } - * }, - * bfetch.createStreamingResponseHandler(async (ctx, req) => { - * const { term } = req.body; - * const results$ = await myApi.getResults$(term); - * return results$; - * }) - * )} - * - * ``` - * - * @param streamHandler - */ - createStreamingRequestHandler: < - Response, - P, - Q, - B, - Context extends RequestHandlerContext = RequestHandlerContext, - Method extends RouteMethod = any - >( - streamHandler: StreamingRequestHandler - ) => RequestHandler; } // eslint-disable-next-line @@ -124,15 +82,10 @@ export class BfetchServerPlugin logger, }); const addBatchProcessingRoute = this.addBatchProcessingRoute(addStreamingResponseRoute); - const createStreamingRequestHandler = this.createStreamingRequestHandler({ - getStartServices: core.getStartServices, - logger, - }); return { addBatchProcessingRoute, addStreamingResponseRoute, - createStreamingRequestHandler, }; } @@ -142,10 +95,6 @@ export class BfetchServerPlugin public stop() {} - private getCompressionDisabled(request: KibanaRequest) { - return request.headers['x-chunk-encoding'] !== 'deflate'; - } - private addStreamingResponseRoute = ({ getStartServices, @@ -162,42 +111,21 @@ export class BfetchServerPlugin path: `/${removeLeadingSlash(path)}`, validate: { body: schema.any(), + query: schema.object({ compress: schema.boolean({ defaultValue: false }) }), }, }, async (context, request, response) => { const handlerInstance = handler(request); const data = request.body; - const compressionDisabled = this.getCompressionDisabled(request); + const compress = request.query.compress; return response.ok({ headers: streamingHeaders, - body: createStream( - handlerInstance.getResponseStream(data), - logger, - compressionDisabled - ), + body: createStream(handlerInstance.getResponseStream(data), logger, compress), }); } ); }; - private createStreamingRequestHandler = - ({ - logger, - getStartServices, - }: { - logger: Logger; - getStartServices: StartServicesAccessor; - }): BfetchServerSetup['createStreamingRequestHandler'] => - (streamHandler) => - async (context, request, response) => { - const response$ = await streamHandler(context, request); - const compressionDisabled = this.getCompressionDisabled(request); - return response.ok({ - headers: streamingHeaders, - body: createStream(response$, logger, compressionDisabled), - }); - }; - private addBatchProcessingRoute = ( addStreamingResponseRoute: BfetchServerSetup['addStreamingResponseRoute'] diff --git a/src/plugins/bfetch/server/streaming/create_stream.ts b/src/plugins/bfetch/server/streaming/create_stream.ts index 7d6981294341b..756a806a60229 100644 --- a/src/plugins/bfetch/server/streaming/create_stream.ts +++ b/src/plugins/bfetch/server/streaming/create_stream.ts @@ -15,9 +15,9 @@ import { createNDJSONStream } from './create_ndjson_stream'; export function createStream( response$: Observable, logger: Logger, - compressionDisabled: boolean + compress: boolean ): Stream { - return compressionDisabled - ? createNDJSONStream(response$, logger) - : createCompressedStream(response$, logger); + return compress + ? createCompressedStream(response$, logger) + : createNDJSONStream(response$, logger); } diff --git a/src/plugins/bfetch/server/types.ts b/src/plugins/bfetch/server/types.ts deleted file mode 100644 index 4e54744f4c374..0000000000000 --- a/src/plugins/bfetch/server/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Observable } from 'rxjs'; -import { KibanaRequest, RequestHandlerContext, RouteMethod } from 'kibana/server'; - -/** - * Request handler modified to allow to return an observable. - * - * See {@link BfetchServerSetup.createStreamingRequestHandler} for usage example. - * @public - */ -export type StreamingRequestHandler< - Response = unknown, - P = unknown, - Q = unknown, - B = unknown, - Method extends RouteMethod = any -> = ( - context: RequestHandlerContext, - request: KibanaRequest -) => Observable | Promise>; diff --git a/test/api_integration/apis/search/bsearch.ts b/test/api_integration/apis/search/bsearch.ts index f80bc1d0d9dfa..6aee2b542da0f 100644 --- a/test/api_integration/apis/search/bsearch.ts +++ b/test/api_integration/apis/search/bsearch.ts @@ -29,28 +29,25 @@ export default function ({ getService }: FtrProviderContext) { describe('bsearch', () => { describe('post', () => { it('should return 200 a single response', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set({ 'X-Chunk-Encoding': '' }) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, + const resp = await supertest.post(`/internal/bsearch`).send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, }, }, }, - options: { - strategy: 'es', - }, }, - ], - }); + options: { + strategy: 'es', + }, + }, + ], + }); const jsonBody = parseBfetchResponse(resp); @@ -62,28 +59,25 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 200 a single response from compressed', async () => { - const resp = await supertest - .post(`/internal/bsearch`) - .set({ 'X-Chunk-Encoding': 'deflate' }) - .send({ - batch: [ - { - request: { - params: { - index: '.kibana', - body: { - query: { - match_all: {}, - }, + const resp = await supertest.post(`/internal/bsearch?compress=true`).send({ + batch: [ + { + request: { + params: { + index: '.kibana', + body: { + query: { + match_all: {}, }, }, }, - options: { - strategy: 'es', - }, }, - ], - }); + options: { + strategy: 'es', + }, + }, + ], + }); const jsonBody = parseBfetchResponse(resp, true); From 32e00f1b0cd9b87a492b2bafa3f8fa2ed46731db Mon Sep 17 00:00:00 2001 From: Kyle Pollich Date: Mon, 11 Oct 2021 11:41:01 -0400 Subject: [PATCH 09/73] [Fleet] Fix previous configuration modal title (#114475) * Fix previous configuration modal title * Revert translation --- .../sections/agent_policy/edit_package_policy_page/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 7a2f46247d14a..4d940534c4a7b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -687,7 +687,7 @@ const UpgradeStatusCallout: React.FunctionComponent<{

From b03237a72d6675bd6deb976a73c2dddcdcb6b445 Mon Sep 17 00:00:00 2001 From: Josh Dover <1813008+joshdover@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:16:26 +0200 Subject: [PATCH 10/73] Enable `bearer` scheme by default to support service token authorization (#112654) Co-authored-by: Aleh Zasypkin --- docs/settings/security-settings.asciidoc | 2 +- .../security/authentication/index.asciidoc | 6 +- .../authentication/authenticator.test.ts | 6 +- x-pack/plugins/security/server/config.test.ts | 9 ++ x-pack/plugins/security/server/config.ts | 2 +- .../security_usage_collector.test.ts | 2 +- x-pack/scripts/functional_tests.js | 1 + .../http_bearer.config.ts | 36 ++++++ .../tests/http_bearer/header.ts | 103 ++++++++++++++++++ .../tests/http_bearer/index.ts | 15 +++ 10 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 x-pack/test/security_api_integration/http_bearer.config.ts create mode 100644 x-pack/test/security_api_integration/tests/http_bearer/header.ts create mode 100644 x-pack/test/security_api_integration/tests/http_bearer/index.ts diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 906af1dfbb28e..11072509da1fc 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -218,7 +218,7 @@ There is a very limited set of cases when you'd want to change these settings. F | Determines if HTTP authentication schemes used by the enabled authentication providers should be automatically supported during HTTP authentication. By default, this setting is set to `true`. | `xpack.security.authc.http.schemes[]` -| List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey']` to support HTTP authentication with <> scheme. +| List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey', 'bearer']` to support HTTP authentication with the <> and <> schemes. |=== diff --git a/docs/user/security/authentication/index.asciidoc b/docs/user/security/authentication/index.asciidoc index bc564308c057e..2f2b279389799 100644 --- a/docs/user/security/authentication/index.asciidoc +++ b/docs/user/security/authentication/index.asciidoc @@ -437,14 +437,14 @@ This type of authentication is usually useful for machine-to-machine interaction By default {kib} supports <> authentication scheme _and_ any scheme supported by the currently enabled authentication provider. For example, `Basic` authentication scheme is automatically supported when basic authentication provider is enabled, or `Bearer` scheme when any of the token based authentication providers is enabled (Token, SAML, OpenID Connect, PKI or Kerberos). But it's also possible to add support for any other authentication scheme in the `kibana.yml` configuration file, as follows: -NOTE: Don't forget to explicitly specify default `apikey` scheme when you just want to add a new one to the list. +NOTE: Don't forget to explicitly specify the default `apikey` and `bearer` schemes when you just want to add a new one to the list. [source,yaml] -------------------------------------------------------------------------------- -xpack.security.authc.http.schemes: [apikey, basic, something-custom] +xpack.security.authc.http.schemes: [apikey, bearer, basic, something-custom] -------------------------------------------------------------------------------- -With this configuration, you can send requests to {kib} with the `Authorization` header using `ApiKey`, `Basic` or `Something-Custom` HTTP schemes (case insensitive). Under the hood, {kib} relays this header to {es}, then {es} authenticates the request using the credentials in the header. +With this configuration, you can send requests to {kib} with the `Authorization` header using `ApiKey`, `Bearer`, `Basic` or `Something-Custom` HTTP schemes (case insensitive). Under the hood, {kib} relays this header to {es}, then {es} authenticates the request using the credentials in the header. [float] [[embedded-content-authentication]] diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index ce97c142f5584..4e35b84a93119 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -210,7 +210,7 @@ describe('Authenticator', () => { expect( jest.requireMock('./providers/http').HTTPAuthenticationProvider ).toHaveBeenCalledWith(expect.anything(), { - supportedSchemes: new Set(['apikey', 'basic']), + supportedSchemes: new Set(['apikey', 'bearer', 'basic']), }); }); @@ -238,7 +238,9 @@ describe('Authenticator', () => { expect( jest.requireMock('./providers/http').HTTPAuthenticationProvider - ).toHaveBeenCalledWith(expect.anything(), { supportedSchemes: new Set(['apikey']) }); + ).toHaveBeenCalledWith(expect.anything(), { + supportedSchemes: new Set(['apikey', 'bearer']), + }); }); it('disabled if explicitly disabled', () => { diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index 4a7d8c7961cf5..1baf3fd4aac50 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -27,6 +27,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Object { @@ -80,6 +81,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Object { @@ -133,6 +135,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Object { @@ -311,6 +314,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "oidc": Object { @@ -342,6 +346,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "oidc": Object { @@ -373,6 +378,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Array [ @@ -391,6 +397,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Array [ @@ -412,6 +419,7 @@ describe('config schema', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Array [ @@ -1485,6 +1493,7 @@ describe('createConfig()', () => { "enabled": true, "schemes": Array [ "apikey", + "bearer", ], }, "providers": Object { diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index 07ff81e092f5f..89918e73369d3 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -269,7 +269,7 @@ export const ConfigSchema = schema.object({ http: schema.object({ enabled: schema.boolean({ defaultValue: true }), autoSchemesEnabled: schema.boolean({ defaultValue: true }), - schemes: schema.arrayOf(schema.string(), { defaultValue: ['apikey'] }), + schemes: schema.arrayOf(schema.string(), { defaultValue: ['apikey', 'bearer'] }), }), }), audit: schema.object( diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts index 0515a1e1969bf..83f09ef017b01 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -46,7 +46,7 @@ describe('Security UsageCollector', () => { authProviderCount: 1, enabledAuthProviders: ['basic'], loginSelectorEnabled: false, - httpAuthSchemes: ['apikey'], + httpAuthSchemes: ['apikey', 'bearer'], sessionIdleTimeoutInMinutes: 60, sessionLifespanInMinutes: 43200, sessionCleanupInMinutes: 60, diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index 3c1cdd5790f3c..f7b978c2b58bd 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -54,6 +54,7 @@ const onlyNotInCoverageTests = [ require.resolve('../test/security_api_integration/session_lifespan.config.ts'), require.resolve('../test/security_api_integration/login_selector.config.ts'), require.resolve('../test/security_api_integration/audit.config.ts'), + require.resolve('../test/security_api_integration/http_bearer.config.ts'), require.resolve('../test/security_api_integration/kerberos.config.ts'), require.resolve('../test/security_api_integration/kerberos_anonymous_access.config.ts'), require.resolve('../test/security_api_integration/pki.config.ts'), diff --git a/x-pack/test/security_api_integration/http_bearer.config.ts b/x-pack/test/security_api_integration/http_bearer.config.ts new file mode 100644 index 0000000000000..b0a9f4a920347 --- /dev/null +++ b/x-pack/test/security_api_integration/http_bearer.config.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from './services'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts')); + + return { + testFiles: [require.resolve('./tests/http_bearer')], + servers: xPackAPITestsConfig.get('servers'), + security: { disableTestUser: true }, + services, + junit: { + reportName: 'X-Pack Security API Integration Tests (HTTP Bearer)', + }, + + esTestCluster: { + ...xPackAPITestsConfig.get('esTestCluster'), + serverArgs: [ + ...xPackAPITestsConfig.get('esTestCluster.serverArgs'), + 'xpack.security.authc.token.enabled=true', + 'xpack.security.authc.token.timeout=15s', + ], + }, + + kbnTestServer: { + ...xPackAPITestsConfig.get('kbnTestServer'), + }, + }; +} diff --git a/x-pack/test/security_api_integration/tests/http_bearer/header.ts b/x-pack/test/security_api_integration/tests/http_bearer/header.ts new file mode 100644 index 0000000000000..f7ebef4f16d09 --- /dev/null +++ b/x-pack/test/security_api_integration/tests/http_bearer/header.ts @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { adminTestUser } from '@kbn/test'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertestWithoutAuth'); + const es = getService('es'); + + async function createToken() { + const { + body: { access_token: accessToken, authentication }, + } = await es.security.getToken({ + body: { + grant_type: 'password', + ...adminTestUser, + }, + }); + + return { + accessToken, + expectedUser: { + ...authentication, + authentication_provider: { name: '__http__', type: 'http' }, + authentication_type: 'token', + }, + }; + } + + describe('header', () => { + it('accepts valid access token via authorization Bearer header', async () => { + const { accessToken, expectedUser } = await createToken(); + + const response = await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', `Bearer ${accessToken}`) + .expect(200, expectedUser); + + // Make sure we don't automatically create a session + expect(response.headers['set-cookie']).to.be(undefined); + }); + + it('accepts multiple requests for a single valid access token', async () => { + const { accessToken, expectedUser } = await createToken(); + + // try it once + await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', `Bearer ${accessToken}`) + .expect(200, expectedUser); + + // try it again to verity it isn't invalidated after a single request + await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', `Bearer ${accessToken}`) + .expect(200, expectedUser); + }); + + it('rejects invalid access token via authorization Bearer header', async () => { + await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', 'Bearer notreal') + .expect(401); + }); + + it('rejects invalidated access token via authorization Bearer header', async () => { + const { accessToken } = await createToken(); + await es.security.invalidateToken({ body: { token: accessToken } }); + + await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', `Bearer ${accessToken}`) + .expect(401); + }); + + it('rejects expired access token via authorization Bearer header', async function () { + this.timeout(40000); + + const { accessToken } = await createToken(); + + // Access token expiration is set to 15s for API integration tests. + // Let's wait for 20s to make sure token expires. + await new Promise((resolve) => setTimeout(resolve, 20000)); + + await supertest + .get('/internal/security/me') + .set('kbn-xsrf', 'true') + .set('authorization', `Bearer ${accessToken}`) + .expect(401); + }); + }); +} diff --git a/x-pack/test/security_api_integration/tests/http_bearer/index.ts b/x-pack/test/security_api_integration/tests/http_bearer/index.ts new file mode 100644 index 0000000000000..4dbad2660ebaa --- /dev/null +++ b/x-pack/test/security_api_integration/tests/http_bearer/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('security APIs - HTTP Bearer', function () { + this.tags('ciGroup6'); + loadTestFile(require.resolve('./header')); + }); +} From c8a01082696a94453060ded28ee67a32a2487e0d Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Mon, 11 Oct 2021 10:53:51 -0600 Subject: [PATCH 11/73] [Stack Monitoring] Adding alerts to react app (#114029) * [Stack Monitoring] Adding alerts to react app * Fixing global state context path * adding alerts to pages; adding alerts model to cluster_overview; removing loadAlerts from page template * Fixing request for enable alerts * remove loadAlerts from page template * Adding request error handlers * removing redundent error handling * Changing useRequestErrorHandler function to be async due to error.response.json call * removing old comment * Fixing contexts paths * Converting ajaxRequestErrorHandler to useRequestErrorHandler * Refactoring error handler for page template and setup mode * Removing unnecessary async/await * Removing unnecessary async/await in useClusters * adding alertTypeIds to each page * fixing instance count * Adding alertTypeIds to index page * Adding alert filters for specific pages * Adding alerts to Logstash nodes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/monitoring/common/types/alerts.ts | 1 + .../public/alerts/alerts_dropdown.tsx | 5 +- .../external_config_context.tsx | 0 .../{ => contexts}/global_state_context.tsx | 8 +- .../contexts/header_action_menu_context.tsx | 15 + .../application/hooks/use_alerts_modal.ts | 10 +- .../public/application/hooks/use_clusters.ts | 6 +- .../application/hooks/use_monitoring_time.ts | 2 +- .../hooks/use_request_error_handler.tsx | 79 +++ .../monitoring/public/application/index.tsx | 467 +++++++++--------- .../public/application/pages/apm/instance.tsx | 2 +- .../application/pages/apm/instances.tsx | 2 +- .../public/application/pages/apm/overview.tsx | 2 +- .../application/pages/beats/instance.tsx | 2 +- .../application/pages/beats/instances.tsx | 2 +- .../application/pages/beats/overview.tsx | 2 +- .../pages/cluster/overview_page.tsx | 49 +- .../pages/elasticsearch/ccr_page.tsx | 41 +- .../pages/elasticsearch/ccr_shard_page.tsx | 47 +- .../elasticsearch/index_advanced_page.tsx | 46 +- .../pages/elasticsearch/index_page.tsx | 58 ++- .../pages/elasticsearch/indices_page.tsx | 51 +- .../pages/elasticsearch/ml_jobs_page.tsx | 2 +- .../elasticsearch/node_advanced_page.tsx | 63 ++- .../pages/elasticsearch/node_page.tsx | 70 ++- .../pages/elasticsearch/nodes_page.tsx | 66 ++- .../pages/elasticsearch/overview.tsx | 2 +- .../pages/home/cluster_listing.tsx | 32 +- .../application/pages/kibana/instance.tsx | 41 +- .../application/pages/kibana/instances.tsx | 43 +- .../application/pages/kibana/overview.tsx | 2 +- .../public/application/pages/license_page.tsx | 2 +- .../application/pages/logstash/advanced.tsx | 41 +- .../application/pages/logstash/node.tsx | 41 +- .../pages/logstash/node_pipelines.tsx | 2 +- .../application/pages/logstash/nodes.tsx | 40 +- .../application/pages/logstash/overview.tsx | 2 +- .../application/pages/logstash/pipeline.tsx | 4 +- .../application/pages/logstash/pipelines.tsx | 2 +- .../pages/no_data/no_data_page.tsx | 6 +- .../application/pages/page_template.tsx | 44 +- .../public/application/route_init.tsx | 2 +- .../application/setup_mode/setup_mode.tsx | 15 +- .../setup_mode/setup_mode_renderer.js | 16 +- .../public/components/action_menu/index.tsx | 34 ++ .../public/components/shared/toolbar.tsx | 2 +- .../monitoring/public/lib/fetch_alerts.ts | 36 ++ 47 files changed, 990 insertions(+), 517 deletions(-) rename x-pack/plugins/monitoring/public/application/{ => contexts}/external_config_context.tsx (100%) rename x-pack/plugins/monitoring/public/application/{ => contexts}/global_state_context.tsx (90%) create mode 100644 x-pack/plugins/monitoring/public/application/contexts/header_action_menu_context.tsx create mode 100644 x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx create mode 100644 x-pack/plugins/monitoring/public/components/action_menu/index.tsx create mode 100644 x-pack/plugins/monitoring/public/lib/fetch_alerts.ts diff --git a/x-pack/plugins/monitoring/common/types/alerts.ts b/x-pack/plugins/monitoring/common/types/alerts.ts index 1f68b0c55a046..bbd217169469d 100644 --- a/x-pack/plugins/monitoring/common/types/alerts.ts +++ b/x-pack/plugins/monitoring/common/types/alerts.ts @@ -32,6 +32,7 @@ export interface CommonAlertState { export interface CommonAlertFilter { nodeUuid?: string; shardId?: string; + shardIndex?: string; } export interface CommonAlertParamDetail { diff --git a/x-pack/plugins/monitoring/public/alerts/alerts_dropdown.tsx b/x-pack/plugins/monitoring/public/alerts/alerts_dropdown.tsx index 261685a532882..976569f39de4c 100644 --- a/x-pack/plugins/monitoring/public/alerts/alerts_dropdown.tsx +++ b/x-pack/plugins/monitoring/public/alerts/alerts_dropdown.tsx @@ -14,13 +14,12 @@ import { import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Legacy } from '../legacy_shims'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { MonitoringStartPluginDependencies } from '../types'; +import { useAlertsModal } from '../application/hooks/use_alerts_modal'; export const AlertsDropdown: React.FC<{}> = () => { - const $injector = Legacy.shims.getAngularInjector(); - const alertsEnableModalProvider: any = $injector.get('enableAlertsModal'); + const alertsEnableModalProvider = useAlertsModal(); const { navigateToApp } = useKibana().services.application; diff --git a/x-pack/plugins/monitoring/public/application/external_config_context.tsx b/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx similarity index 100% rename from x-pack/plugins/monitoring/public/application/external_config_context.tsx rename to x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx diff --git a/x-pack/plugins/monitoring/public/application/global_state_context.tsx b/x-pack/plugins/monitoring/public/application/contexts/global_state_context.tsx similarity index 90% rename from x-pack/plugins/monitoring/public/application/global_state_context.tsx rename to x-pack/plugins/monitoring/public/application/contexts/global_state_context.tsx index 6c952f80eff57..e6638b4c4fede 100644 --- a/x-pack/plugins/monitoring/public/application/global_state_context.tsx +++ b/x-pack/plugins/monitoring/public/application/contexts/global_state_context.tsx @@ -5,10 +5,10 @@ * 2.0. */ import React, { createContext } from 'react'; -import { GlobalState } from '../url_state'; -import { MonitoringStartPluginDependencies } from '../types'; -import { TimeRange, RefreshInterval } from '../../../../../src/plugins/data/public'; -import { Legacy } from '../legacy_shims'; +import { GlobalState } from '../../url_state'; +import { MonitoringStartPluginDependencies } from '../../types'; +import { TimeRange, RefreshInterval } from '../../../../../../src/plugins/data/public'; +import { Legacy } from '../../legacy_shims'; interface GlobalStateProviderProps { query: MonitoringStartPluginDependencies['data']['query']; diff --git a/x-pack/plugins/monitoring/public/application/contexts/header_action_menu_context.tsx b/x-pack/plugins/monitoring/public/application/contexts/header_action_menu_context.tsx new file mode 100644 index 0000000000000..88862d9e6a807 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/contexts/header_action_menu_context.tsx @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { AppMountParameters } from 'kibana/public'; + +interface ContextProps { + setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu']; +} + +export const HeaderActionMenuContext = React.createContext({}); diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_alerts_modal.ts b/x-pack/plugins/monitoring/public/application/hooks/use_alerts_modal.ts index 9a2a2b80cc40f..123dd39f7b54d 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_alerts_modal.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_alerts_modal.ts @@ -6,10 +6,11 @@ */ import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { showAlertsToast } from '../../alerts/lib/alerts_toast'; -import { ajaxErrorHandlersProvider } from '../../lib/ajax_error_handler'; +import { useRequestErrorHandler } from './use_request_error_handler'; export const useAlertsModal = () => { const { services } = useKibana(); + const handleRequestError = useRequestErrorHandler(); function shouldShowAlertsModal(alerts: {}) { const modalHasBeenShown = @@ -28,12 +29,11 @@ export const useAlertsModal = () => { async function enableAlerts() { try { - const { data } = await services.http?.post('../api/monitoring/v1/alerts/enable', {}); + const response = await services.http?.post('../api/monitoring/v1/alerts/enable', {}); window.localStorage.setItem('ALERTS_MODAL_DECISION_MADE', 'true'); - showAlertsToast(data); + showAlertsToast(response); } catch (err) { - const ajaxErrorHandlers = ajaxErrorHandlersProvider(); - return ajaxErrorHandlers(err); + await handleRequestError(err); } } diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts b/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts index b4b8c21ca4d40..1961bd53b909f 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts @@ -7,6 +7,7 @@ import { useState, useEffect } from 'react'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { fetchClusters } from '../../lib/fetch_clusters'; +import { useRequestErrorHandler } from './use_request_error_handler'; export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?: string[]) { const { services } = useKibana<{ data: any }>(); @@ -17,6 +18,7 @@ export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?: const [clusters, setClusters] = useState([] as any); const [loaded, setLoaded] = useState(false); + const handleRequestError = useRequestErrorHandler(); useEffect(() => { async function makeRequest() { @@ -34,13 +36,13 @@ export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?: setClusters(response); } } catch (e) { - // TODO: Handle errors + handleRequestError(e); } finally { setLoaded(true); } } makeRequest(); - }, [clusterUuid, ccs, services.http, codePaths, min, max]); + }, [handleRequestError, clusterUuid, ccs, services.http, codePaths, min, max]); return { clusters, loaded }; } diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts b/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts index 3054714ec3aa6..e8973ce18232c 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts @@ -8,7 +8,7 @@ import { useCallback, useState, useContext, useEffect } from 'react'; import createContainer from 'constate'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { Legacy } from '../../legacy_shims'; -import { GlobalStateContext } from '../../application/global_state_context'; +import { GlobalStateContext } from '../contexts/global_state_context'; interface TimeOptions { from: string; diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx b/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx new file mode 100644 index 0000000000000..3a64531844451 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback } from 'react'; +import { includes } from 'lodash'; +import { IHttpFetchError } from 'kibana/public'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiButton, EuiSpacer, EuiText } from '@elastic/eui'; +import { formatMsg } from '../../../../../../src/plugins/kibana_legacy/public'; +import { toMountPoint, useKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { MonitoringStartPluginDependencies } from '../../types'; + +export function formatMonitoringError(err: IHttpFetchError) { + if (err.response?.status && err.response?.status !== -1) { + return ( + +

{err.body?.message}

+ + + +
+ ); + } + + return formatMsg(err); +} + +export const useRequestErrorHandler = () => { + const { services } = useKibana(); + return useCallback( + (err: IHttpFetchError) => { + if (err.response?.status === 403) { + // redirect to error message view + history.replaceState(null, '', '#/access-denied'); + } else if (err.response?.status === 404 && !includes(window.location.hash, 'no-data')) { + // pass through if this is a 404 and we're already on the no-data page + const formattedError = formatMonitoringError(err); + services.notifications?.toasts.addDanger({ + title: toMountPoint( + + ), + text: toMountPoint( +
+ {formattedError} + + window.location.reload()}> + + +
+ ), + }); + } else { + services.notifications?.toasts.addDanger({ + title: toMountPoint( + + ), + text: toMountPoint(formatMonitoringError(err)), + }); + } + }, + [services.notifications] + ); +}; diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx index bc81dd826f849..7b4c73475338f 100644 --- a/x-pack/plugins/monitoring/public/application/index.tsx +++ b/x-pack/plugins/monitoring/public/application/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { CoreStart, AppMountParameters } from 'kibana/public'; +import { CoreStart, AppMountParameters, MountPoint } from 'kibana/public'; import React from 'react'; import ReactDOM from 'react-dom'; import { Route, Switch, Redirect, Router } from 'react-router-dom'; @@ -15,8 +15,8 @@ import { LicensePage } from './pages/license_page'; import { ClusterOverview } from './pages/cluster/overview_page'; import { ClusterListing } from './pages/home/cluster_listing'; import { MonitoringStartPluginDependencies } from '../types'; -import { GlobalStateProvider } from './global_state_context'; -import { ExternalConfigContext, ExternalConfig } from './external_config_context'; +import { GlobalStateProvider } from './contexts/global_state_context'; +import { ExternalConfigContext, ExternalConfig } from './contexts/external_config_context'; import { createPreserveQueryHistory } from './preserve_query_history'; import { RouteInit } from './route_init'; import { NoDataPage } from './pages/no_data'; @@ -45,6 +45,7 @@ import { ElasticsearchCcrPage } from './pages/elasticsearch/ccr_page'; import { ElasticsearchCcrShardPage } from './pages/elasticsearch/ccr_shard_page'; import { MonitoringTimeContainer } from './hooks/use_monitoring_time'; import { BreadcrumbContainer } from './hooks/use_breadcrumbs'; +import { HeaderActionMenuContext } from './contexts/header_action_menu_context'; import { LogStashOverviewPage } from './pages/logstash/overview'; import { LogStashNodesPage } from './pages/logstash/nodes'; import { LogStashPipelinesPage } from './pages/logstash/pipelines'; @@ -58,11 +59,16 @@ import { LogStashNodePipelinesPage } from './pages/logstash/node_pipelines'; export const renderApp = ( core: CoreStart, plugins: MonitoringStartPluginDependencies, - { element }: AppMountParameters, + { element, setHeaderActionMenu }: AppMountParameters, externalConfig: ExternalConfig ) => { ReactDOM.render( - , + , element ); @@ -75,236 +81,239 @@ const MonitoringApp: React.FC<{ core: CoreStart; plugins: MonitoringStartPluginDependencies; externalConfig: ExternalConfig; -}> = ({ core, plugins, externalConfig }) => { + setHeaderActionMenu: (element: MountPoint | undefined) => void; +}> = ({ core, plugins, externalConfig, setHeaderActionMenu }) => { const history = createPreserveQueryHistory(); return ( - - - - - - - - - - - {/* ElasticSearch Views */} - - - - - - - - - - - - - - - - - - - - - {/* Kibana Views */} - - - - - - - {/* Beats Views */} - - - - - - - {/* Logstash Routes */} - - - - - - - - - - - - - - - {/* APM Views */} - - - - - - - - - - - + + + + + + + + + + + + {/* ElasticSearch Views */} + + + + + + + + + + + + + + + + + + + + + {/* Kibana Views */} + + + + + + + {/* Beats Views */} + + + + + + + {/* Logstash Routes */} + + + + + + + + + + + + + + + {/* APM Views */} + + + + + + + + + + + + diff --git a/x-pack/plugins/monitoring/public/application/pages/apm/instance.tsx b/x-pack/plugins/monitoring/public/application/pages/apm/instance.tsx index dc55ecb22b61a..3fa7819c5e417 100644 --- a/x-pack/plugins/monitoring/public/application/pages/apm/instance.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/apm/instance.tsx @@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useCharts } from '../../hooks/use_charts'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; diff --git a/x-pack/plugins/monitoring/public/application/pages/apm/instances.tsx b/x-pack/plugins/monitoring/public/application/pages/apm/instances.tsx index bc60f26cdbfad..fedb07fa65a40 100644 --- a/x-pack/plugins/monitoring/public/application/pages/apm/instances.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/apm/instances.tsx @@ -9,7 +9,7 @@ import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useTable } from '../../hooks/use_table'; import { ApmTemplate } from './apm_template'; diff --git a/x-pack/plugins/monitoring/public/application/pages/apm/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/apm/overview.tsx index cca31c0a7e65d..516c293c53546 100644 --- a/x-pack/plugins/monitoring/public/application/pages/apm/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/apm/overview.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; import { ApmTemplate } from './apm_template'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useCharts } from '../../hooks/use_charts'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx index f7ff03898fda6..4c66bbba631fb 100644 --- a/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx @@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useCharts } from '../../hooks/use_charts'; // @ts-ignore diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx index 18f941c398af0..489ad110c40fd 100644 --- a/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx @@ -9,7 +9,7 @@ import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useTable } from '../../hooks/use_table'; import { BeatsTemplate } from './beats_template'; diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx index 8d28119c4ec1b..1fa37a2c7b3e6 100644 --- a/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; import { BeatsTemplate } from './beats_template'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useCharts } from '../../hooks/use_charts'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; // @ts-ignore diff --git a/x-pack/plugins/monitoring/public/application/pages/cluster/overview_page.tsx b/x-pack/plugins/monitoring/public/application/pages/cluster/overview_page.tsx index 3a717036396e9..b78df27cd12c4 100644 --- a/x-pack/plugins/monitoring/public/application/pages/cluster/overview_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/cluster/overview_page.tsx @@ -10,14 +10,17 @@ import { i18n } from '@kbn/i18n'; import { CODE_PATH_ALL } from '../../../../common/constants'; import { PageTemplate } from '../page_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { TabMenuItem } from '../page_template'; import { Overview } from '../../../components/cluster/overview'; -import { ExternalConfigContext } from '../../external_config_context'; +import { ExternalConfigContext } from '../../contexts/external_config_context'; import { SetupModeRenderer, SetupModeProps } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; import { fetchClusters } from '../../../lib/fetch_clusters'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { EnableAlertsModal } from '../../../alerts/enable_alerts_modal'; const CODE_PATHS = [CODE_PATH_ALL]; @@ -28,6 +31,7 @@ export const ClusterOverview: React.FC<{}> = () => { const clusterUuid = state.cluster_uuid; const ccs = state.ccs; const [clusters, setClusters] = useState([] as any); + const [alerts, setAlerts] = useState({}); const [loaded, setLoaded] = useState(false); const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); @@ -54,23 +58,27 @@ export const ClusterOverview: React.FC<{}> = () => { const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); - try { - if (services.http?.fetch) { - const response = await fetchClusters({ - fetch: services.http.fetch, - timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), - }, - ccs, - clusterUuid, - codePaths: CODE_PATHS, - }); - setClusters(response); - } - } catch (err) { - // TODO: handle errors - } finally { + if (services.http?.fetch && clusterUuid) { + const response = await fetchClusters({ + fetch: services.http.fetch, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + ccs, + clusterUuid, + codePaths: CODE_PATHS, + }); + setClusters(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + clusterUuid, + timeRange: { + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), + }, + }); + setAlerts(alertsResponse); setLoaded(true); } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]); @@ -89,7 +97,7 @@ export const ClusterOverview: React.FC<{}> = () => { {flyoutComponent} @@ -98,6 +106,7 @@ export const ClusterOverview: React.FC<{}> = () => { )} /> + ); }; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx index 294aeade5e38b..8a9a736286c3f 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx @@ -9,13 +9,15 @@ import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; // @ts-ignore import { Ccr } from '../../../components/elasticsearch/ccr'; import { ComponentProps } from '../../route_init'; import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; -import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { ELASTICSEARCH_SYSTEM_ID, RULE_CCR_READ_EXCEPTIONS } from '../../../../common/constants'; interface SetupModeProps { setupMode: any; @@ -33,6 +35,7 @@ export const ElasticsearchCcrPage: React.FC = ({ clusters }) => }) as any; const ccs = globalState.ccs; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.ccr.title', { defaultMessage: 'Elasticsearch - Ccr', @@ -46,18 +49,30 @@ export const ElasticsearchCcrPage: React.FC = ({ clusters }) => const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/ccr`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_CCR_READ_EXCEPTIONS], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]); return ( @@ -73,7 +88,7 @@ export const ElasticsearchCcrPage: React.FC = ({ clusters }) => render={({ flyoutComponent, bottomBarComponent }: SetupModeProps) => ( {flyoutComponent} - + {bottomBarComponent} )} diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx index bec2f278f1774..21f9fd10f0806 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx @@ -10,13 +10,15 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; import { PageTemplate } from '../page_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; // @ts-ignore import { CcrShardReact } from '../../../components/elasticsearch/ccr_shard'; import { ComponentProps } from '../../route_init'; import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; -import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { ELASTICSEARCH_SYSTEM_ID, RULE_CCR_READ_EXCEPTIONS } from '../../../../common/constants'; interface SetupModeProps { setupMode: any; @@ -24,7 +26,7 @@ interface SetupModeProps { bottomBarComponent: any; } -export const ElasticsearchCcrShardPage: React.FC = ({ clusters }) => { +export const ElasticsearchCcrShardPage: React.FC = () => { const globalState = useContext(GlobalStateContext); const { services } = useKibana<{ data: any }>(); const { index, shardId }: { index: string; shardId: string } = useParams(); @@ -32,6 +34,7 @@ export const ElasticsearchCcrShardPage: React.FC = ({ clusters } const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.ccr.shard.title', { defaultMessage: 'Elasticsearch - Ccr - Shard', @@ -57,18 +60,34 @@ export const ElasticsearchCcrShardPage: React.FC = ({ clusters } const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/ccr/${index}/shard/${shardId}`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_CCR_READ_EXCEPTIONS], + clusterUuid, + filters: [ + { + shardId, + }, + ], timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http, index, shardId]); return ( @@ -84,7 +103,7 @@ export const ElasticsearchCcrShardPage: React.FC = ({ clusters } render={({ flyoutComponent, bottomBarComponent }: SetupModeProps) => ( {flyoutComponent} - + {bottomBarComponent} )} diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx index a635d98fcbbb0..86dba4e2f921c 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx @@ -8,7 +8,7 @@ import React, { useContext, useState, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { useParams } from 'react-router-dom'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; import { SetupModeRenderer, SetupModeProps } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; @@ -16,15 +16,18 @@ import { useCharts } from '../../hooks/use_charts'; import { ItemTemplate } from './item_template'; // @ts-ignore import { AdvancedIndex } from '../../../components/elasticsearch/index/advanced'; -import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { ELASTICSEARCH_SYSTEM_ID, RULE_LARGE_SHARD_SIZE } from '../../../../common/constants'; -export const ElasticsearchIndexAdvancedPage: React.FC = ({ clusters }) => { +export const ElasticsearchIndexAdvancedPage: React.FC = () => { const globalState = useContext(GlobalStateContext); const { services } = useKibana<{ data: any }>(); const { index }: { index: string } = useParams(); const { zoomInfo, onBrush } = useCharts(); const clusterUuid = globalState.cluster_uuid; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.index.advanced.title', { defaultMessage: 'Elasticsearch - Indices - {indexName} - Advanced', @@ -36,17 +39,34 @@ export const ElasticsearchIndexAdvancedPage: React.FC = ({ clust const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices/${index}`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: true, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_LARGE_SHARD_SIZE], + filters: [ + { + shardIndex: index, + }, + ], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: true, - }), - }); - setData(response); + }); + setAlerts(alertsResponse); + } }, [clusterUuid, services.data?.query.timefilter.timefilter, services.http, index]); return ( @@ -58,7 +78,7 @@ export const ElasticsearchIndexAdvancedPage: React.FC = ({ clust {flyoutComponent} = ({ clusters }) => { +export const ElasticsearchIndexPage: React.FC = () => { const globalState = useContext(GlobalStateContext); const { services } = useKibana<{ data: any }>(); const { index }: { index: string } = useParams(); @@ -31,6 +33,7 @@ export const ElasticsearchIndexPage: React.FC = ({ clusters }) = const [data, setData] = useState({} as any); const [indexLabel, setIndexLabel] = useState(labels.index as any); const [nodesByIndicesData, setNodesByIndicesData] = useState([]); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.index.overview.title', { defaultMessage: 'Elasticsearch - Indices - {indexName} - Overview', @@ -49,23 +52,40 @@ export const ElasticsearchIndexPage: React.FC = ({ clusters }) = const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices/${index}`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: false, + }), + }); + setData(response); + const transformer = indicesByNodes(); + setNodesByIndicesData(transformer(response.shards, response.nodes)); + + const shards = response.shards; + if (shards.some((shard: any) => shard.state === 'UNASSIGNED')) { + setIndexLabel(labels.indexWithUnassigned); + } + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_LARGE_SHARD_SIZE], + filters: [ + { + shardIndex: index, + }, + ], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: false, - }), - }); - setData(response); - const transformer = indicesByNodes(); - setNodesByIndicesData(transformer(response.shards, response.nodes)); - - const shards = response.shards; - if (shards.some((shard: any) => shard.state === 'UNASSIGNED')) { - setIndexLabel(labels.indexWithUnassigned); + }); + setAlerts(alertsResponse); } }, [clusterUuid, services.data?.query.timefilter.timefilter, services.http, index]); @@ -85,7 +105,7 @@ export const ElasticsearchIndexPage: React.FC = ({ clusters }) = = ({ clusters }) => { const globalState = useContext(GlobalStateContext); @@ -32,6 +34,7 @@ export const ElasticsearchIndicesPage: React.FC = ({ clusters }) 'showSystemIndices', false ); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.indices.routeTitle', { defaultMessage: 'Elasticsearch - Indices', @@ -49,26 +52,38 @@ export const ElasticsearchIndicesPage: React.FC = ({ clusters }) const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices`; - const response = await services.http?.fetch(url, { - method: 'POST', - query: { - show_system_indices: showSystemIndices, - }, - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + query: { + show_system_indices: showSystemIndices, + }, + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + clusterUuid, + alertTypeIds: [RULE_LARGE_SHARD_SIZE], timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - setData(response); + }); + setAlerts(alertsResponse); + } }, [ - ccs, - showSystemIndices, - clusterUuid, services.data?.query.timefilter.timefilter, services.http, + clusterUuid, + showSystemIndices, + ccs, ]); return ( @@ -88,7 +103,7 @@ export const ElasticsearchIndicesPage: React.FC = ({ clusters }) = ({ clusters }) => { +export const ElasticsearchNodeAdvancedPage: React.FC = () => { const globalState = useContext(GlobalStateContext); const { zoomInfo, onBrush } = useCharts(); @@ -25,6 +35,7 @@ export const ElasticsearchNodeAdvancedPage: React.FC = ({ cluste const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.node.advanced.title', { defaultMessage: 'Elasticsearch - Nodes - {nodeName} - Advanced', @@ -43,20 +54,42 @@ export const ElasticsearchNodeAdvancedPage: React.FC = ({ cluste const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes/${node}`; - - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: true, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + clusterUuid, + alertTypeIds: [ + RULE_CPU_USAGE, + RULE_THREAD_POOL_SEARCH_REJECTIONS, + RULE_THREAD_POOL_WRITE_REJECTIONS, + RULE_MISSING_MONITORING_DATA, + RULE_DISK_USAGE, + RULE_MEMORY_USAGE, + ], + filters: [ + { + nodeUuid: node, + }, + ], timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: true, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http, node]); return ( @@ -69,7 +102,7 @@ export const ElasticsearchNodeAdvancedPage: React.FC = ({ cluste > = ({ clusters }) => { +export const ElasticsearchNodePage: React.FC = () => { const globalState = useContext(GlobalStateContext); const { zoomInfo, onBrush } = useCharts(); const [showSystemIndices, setShowSystemIndices] = useLocalStorage( 'showSystemIndices', false ); + const [alerts, setAlerts] = useState({}); const { node }: { node: string } = useParams(); const { services } = useKibana<{ data: any }>(); @@ -54,30 +65,49 @@ export const ElasticsearchNodePage: React.FC = ({ clusters }) => const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes/${node}`; + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + showSystemIndices, + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: false, + }), + }); - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - showSystemIndices, - ccs, + setData(response); + const transformer = nodesByIndices(); + setNodesByIndicesData(transformer(response.shards, response.nodes)); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [ + RULE_CPU_USAGE, + RULE_THREAD_POOL_SEARCH_REJECTIONS, + RULE_THREAD_POOL_WRITE_REJECTIONS, + RULE_MISSING_MONITORING_DATA, + RULE_DISK_USAGE, + RULE_MEMORY_USAGE, + ], + filters: [{ nodeUuid: node }], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: false, - }), - }); - - setData(response); - const transformer = nodesByIndices(); - setNodesByIndicesData(transformer(response.shards, response.nodes)); + }); + setAlerts(alertsResponse); + } }, [ - ccs, - clusterUuid, services.data?.query.timefilter.timefilter, services.http, + clusterUuid, node, showSystemIndices, + ccs, ]); const toggleShowSystemIndices = useCallback(() => { @@ -98,7 +128,7 @@ export const ElasticsearchNodePage: React.FC = ({ clusters }) => {flyoutComponent} = ({ clusters }) => { const globalState = useContext(GlobalStateContext); @@ -32,6 +42,7 @@ export const ElasticsearchNodesPage: React.FC = ({ clusters }) = cluster_uuid: clusterUuid, }) as any; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.nodes.routeTitle', { defaultMessage: 'Elasticsearch - Nodes', @@ -52,25 +63,44 @@ export const ElasticsearchNodesPage: React.FC = ({ clusters }) = const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + ...getPaginationRouteOptions(), + }), + }); + + setData(response); + updateTotalItemCount(response.totalNodeCount); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + clusterUuid, + alertTypeIds: [ + RULE_CPU_USAGE, + RULE_DISK_USAGE, + RULE_THREAD_POOL_SEARCH_REJECTIONS, + RULE_THREAD_POOL_WRITE_REJECTIONS, + RULE_MEMORY_USAGE, + RULE_MISSING_MONITORING_DATA, + ], timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - ...getPaginationRouteOptions(), - }), - }); - - setData(response); - updateTotalItemCount(response.totalNodeCount); + }); + setAlerts(alertsResponse); + } }, [ - ccs, - clusterUuid, services.data?.query.timefilter.timefilter, services.http, + clusterUuid, + ccs, getPaginationRouteOptions, updateTotalItemCount, ]); @@ -94,7 +124,7 @@ export const ElasticsearchNodesPage: React.FC = ({ clusters }) = clusterUuid={globalState.cluster_uuid} setupMode={setupMode} nodes={data.nodes} - alerts={{}} + alerts={alerts} showCgroupMetricsElasticsearch={showCgroupMetricsElasticsearch} {...getPaginationTableProps()} /> diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx index 3334c7e7b880a..c58aaa5dffb04 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ElasticsearchOverview } from '../../../components/elasticsearch'; import { ComponentProps } from '../../route_init'; import { useCharts } from '../../hooks/use_charts'; diff --git a/x-pack/plugins/monitoring/public/application/pages/home/cluster_listing.tsx b/x-pack/plugins/monitoring/public/application/pages/home/cluster_listing.tsx index 906db1b57f0f5..a31f2bc317fa6 100644 --- a/x-pack/plugins/monitoring/public/application/pages/home/cluster_listing.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/home/cluster_listing.tsx @@ -12,8 +12,8 @@ import { useKibana } from '../../../../../../../src/plugins/kibana_react/public' // @ts-ignore import { Listing } from '../../../components/cluster/listing'; import { EnableAlertsModal } from '../../../alerts/enable_alerts_modal'; -import { GlobalStateContext } from '../../global_state_context'; -import { ExternalConfigContext } from '../../external_config_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; +import { ExternalConfigContext } from '../../contexts/external_config_context'; import { ComponentProps } from '../../route_init'; import { useTable } from '../../hooks/use_table'; import { PageTemplate, TabMenuItem } from '../page_template'; @@ -69,23 +69,19 @@ export const ClusterListing: React.FC = () => { const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); - try { - if (services.http?.fetch) { - const response = await fetchClusters({ - fetch: services.http.fetch, - timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), - }, - ccs: globalState.ccs, - codePaths: ['all'], - }); - setClusters(response); - } - } catch (err) { - // TODO: handle errors + if (services.http?.fetch) { + const response = await fetchClusters({ + fetch: services.http.fetch, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + ccs: globalState.ccs, + codePaths: ['all'], + }); + setClusters(response); } - }, [globalState, services.data?.query.timefilter.timefilter, services.http]); + }, [globalState.ccs, services.data?.query.timefilter.timefilter, services.http]); if (globalState.save && clusters.length === 1) { globalState.cluster_uuid = clusters[0].cluster_uuid; diff --git a/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx b/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx index 8b88fc47a9007..444794d118b0f 100644 --- a/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx @@ -19,7 +19,7 @@ import { EuiPanel, } from '@elastic/eui'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useCharts } from '../../hooks/use_charts'; // @ts-ignore @@ -30,6 +30,9 @@ import { MonitoringTimeseriesContainer } from '../../../components/chart'; import { DetailStatus } from '../../../components/kibana/detail_status'; import { PageTemplate } from '../page_template'; import { AlertsCallout } from '../../../alerts/callout'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { RULE_KIBANA_VERSION_MISMATCH } from '../../../../common/constants'; const KibanaInstance = ({ data, alerts }: { data: any; alerts: any }) => { const { zoomInfo, onBrush } = useCharts(); @@ -112,6 +115,7 @@ export const KibanaInstancePage: React.FC = ({ clusters }) => { }) as any; const [data, setData] = useState({} as any); const [instanceName, setInstanceName] = useState(''); + const [alerts, setAlerts] = useState({}); const title = `Kibana - ${instanceName}`; const pageTitle = i18n.translate('xpack.monitoring.kibana.instance.pageTitle', { @@ -133,19 +137,30 @@ export const KibanaInstancePage: React.FC = ({ clusters }) => { const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/kibana/${instance}`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + setData(response); + setInstanceName(response.kibanaSummary.name); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_KIBANA_VERSION_MISMATCH], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - - setData(response); - setInstanceName(response.kibanaSummary.name); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, instance, services.data?.query.timefilter.timefilter, services.http]); return ( @@ -156,7 +171,7 @@ export const KibanaInstancePage: React.FC = ({ clusters }) => { data-test-subj="kibanaInstancePage" >
- +
); diff --git a/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx b/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx index 436a1a72b2fdb..ae0237ea40472 100644 --- a/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx @@ -9,7 +9,7 @@ import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ComponentProps } from '../../route_init'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useTable } from '../../hooks/use_table'; import { KibanaTemplate } from './kibana_template'; @@ -19,7 +19,9 @@ import { KibanaInstances } from '../../../components/kibana/instances'; import { SetupModeRenderer, SetupModeProps } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; -import { KIBANA_SYSTEM_ID } from '../../../../common/constants'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { KIBANA_SYSTEM_ID, RULE_KIBANA_VERSION_MISMATCH } from '../../../../common/constants'; export const KibanaInstancesPage: React.FC = ({ clusters }) => { const { cluster_uuid: clusterUuid, ccs } = useContext(GlobalStateContext); @@ -30,6 +32,7 @@ export const KibanaInstancesPage: React.FC = ({ clusters }) => { cluster_uuid: clusterUuid, }) as any; const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.kibana.instances.routeTitle', { defaultMessage: 'Kibana - Instances', @@ -50,19 +53,31 @@ export const KibanaInstancesPage: React.FC = ({ clusters }) => { const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/kibana/instances`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + + setData(response); + updateTotalItemCount(response.kibanas.length); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_KIBANA_VERSION_MISMATCH], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - - setData(response); - updateTotalItemCount(response.stats.total); + }); + setAlerts(alertsResponse); + } }, [ ccs, clusterUuid, @@ -85,7 +100,7 @@ export const KibanaInstancesPage: React.FC = ({ clusters }) => { {flyoutComponent} = ({ clusters }) => { const globalState = useContext(GlobalStateContext); @@ -42,6 +45,7 @@ export const LogStashNodeAdvancedPage: React.FC = ({ clusters }) }); const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.logstash.node.advanced.routeTitle', { defaultMessage: 'Logstash - {nodeName} - Advanced', @@ -60,19 +64,30 @@ export const LogStashNodeAdvancedPage: React.FC = ({ clusters }) const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/logstash/node/${match.params.uuid}`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: true, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_LOGSTASH_VERSION_MISMATCH], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: true, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ ccs, clusterUuid, @@ -105,7 +120,7 @@ export const LogStashNodeAdvancedPage: React.FC = ({ clusters }) {data.nodeSummary && } - + {metricsToShow.map((metric, index) => ( diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/node.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/node.tsx index 301d3c45dedb5..1163a619dd84b 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/node.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/node.tsx @@ -18,7 +18,7 @@ import { EuiFlexItem, } from '@elastic/eui'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; // @ts-ignore import { List } from '../../../components/logstash/pipeline_viewer/models/list'; @@ -30,6 +30,9 @@ import { DetailStatus } from '../../../components/logstash/detail_status'; import { MonitoringTimeseriesContainer } from '../../../components/chart'; import { AlertsCallout } from '../../../alerts/callout'; import { useCharts } from '../../hooks/use_charts'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; +import { RULE_LOGSTASH_VERSION_MISMATCH } from '../../../../common/constants'; export const LogStashNodePage: React.FC = ({ clusters }) => { const match = useRouteMatch<{ uuid: string | undefined }>(); @@ -41,6 +44,7 @@ export const LogStashNodePage: React.FC = ({ clusters }) => { cluster_uuid: clusterUuid, }); const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const { zoomInfo, onBrush } = useCharts(); const title = i18n.translate('xpack.monitoring.logstash.node.routeTitle', { defaultMessage: 'Logstash - {nodeName}', @@ -59,19 +63,30 @@ export const LogStashNodePage: React.FC = ({ clusters }) => { const getPageData = useCallback(async () => { const url = `../api/monitoring/v1/clusters/${clusterUuid}/logstash/node/${match.params.uuid}`; const bounds = services.data?.query.timefilter.timefilter.getBounds(); - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: false, + }), + }); + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_LOGSTASH_VERSION_MISMATCH], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - is_advanced: false, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http, match.params]); const metricsToShow = useMemo(() => { @@ -99,7 +114,7 @@ export const LogStashNodePage: React.FC = ({ clusters }) => { {data.nodeSummary && } - + {metricsToShow.map((metric, index) => ( diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/node_pipelines.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/node_pipelines.tsx index 1c956603f99bd..e09850eaad5c9 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/node_pipelines.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/node_pipelines.tsx @@ -12,7 +12,7 @@ import { useRouteMatch } from 'react-router-dom'; // @ts-ignore import { isPipelineMonitoringSupportedInVersion } from '../../../lib/logstash/pipelines'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; // @ts-ignore import { Listing } from '../../../components/logstash/listing'; diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/nodes.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/nodes.tsx index 09a97925c56f5..0fd10a93bcd83 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/nodes.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/nodes.tsx @@ -8,7 +8,7 @@ import React, { useContext, useState, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; // @ts-ignore import { Listing } from '../../../components/logstash/listing'; @@ -16,7 +16,9 @@ import { LogstashTemplate } from './logstash_template'; import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; import { useTable } from '../../hooks/use_table'; -import { LOGSTASH_SYSTEM_ID } from '../../../../common/constants'; +import { LOGSTASH_SYSTEM_ID, RULE_LOGSTASH_VERSION_MISMATCH } from '../../../../common/constants'; +import { AlertsByName } from '../../../alerts/types'; +import { fetchAlerts } from '../../../lib/fetch_alerts'; interface SetupModeProps { setupMode: any; @@ -33,6 +35,7 @@ export const LogStashNodesPage: React.FC = ({ clusters }) => { cluster_uuid: clusterUuid, }); const [data, setData] = useState({} as any); + const [alerts, setAlerts] = useState({}); const { getPaginationTableProps } = useTable('logstash.nodes'); const title = i18n.translate('xpack.monitoring.logstash.nodes.routeTitle', { @@ -46,18 +49,30 @@ export const LogStashNodesPage: React.FC = ({ clusters }) => { const getPageData = useCallback(async () => { const bounds = services.data?.query.timefilter.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${clusterUuid}/logstash/nodes`; - const response = await services.http?.fetch(url, { - method: 'POST', - body: JSON.stringify({ - ccs, + if (services.http?.fetch && clusterUuid) { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + + setData(response); + const alertsResponse = await fetchAlerts({ + fetch: services.http.fetch, + alertTypeIds: [RULE_LOGSTASH_VERSION_MISMATCH], + clusterUuid, timeRange: { - min: bounds.min.toISOString(), - max: bounds.max.toISOString(), + min: bounds.min.valueOf(), + max: bounds.max.valueOf(), }, - }), - }); - - setData(response); + }); + setAlerts(alertsResponse); + } }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]); return ( @@ -78,6 +93,7 @@ export const LogStashNodesPage: React.FC = ({ clusters }) => { metrics={data.metrics} data={data.nodes} setupMode={setupMode} + alerts={alerts} {...getPaginationTableProps()} /> {bottomBarComponent} diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/overview.tsx index 1edbe5cf71e7d..339b9e9395569 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/overview.tsx @@ -8,7 +8,7 @@ import React, { useContext, useState, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; import { useCharts } from '../../hooks/use_charts'; // @ts-ignore diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx index abff0ab17b992..20f1caee2b1d8 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/pipeline.tsx @@ -10,7 +10,7 @@ import { find } from 'lodash'; import moment from 'moment'; import { useRouteMatch } from 'react-router-dom'; import { useKibana, useUiSetting } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; // @ts-ignore import { List } from '../../../components/logstash/pipeline_viewer/models/list'; @@ -24,7 +24,7 @@ import { PipelineState } from '../../../components/logstash/pipeline_viewer/mode import { vertexFactory } from '../../../components/logstash/pipeline_viewer/models/graph/vertex_factory'; import { LogstashTemplate } from './logstash_template'; import { useTable } from '../../hooks/use_table'; -import { ExternalConfigContext } from '../../external_config_context'; +import { ExternalConfigContext } from '../../contexts/external_config_context'; import { formatTimestampToDuration } from '../../../../common'; import { CALCULATE_DURATION_SINCE } from '../../../../common/constants'; import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; diff --git a/x-pack/plugins/monitoring/public/application/pages/logstash/pipelines.tsx b/x-pack/plugins/monitoring/public/application/pages/logstash/pipelines.tsx index 5f4fe634177de..ac750ff81ddaa 100644 --- a/x-pack/plugins/monitoring/public/application/pages/logstash/pipelines.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/logstash/pipelines.tsx @@ -8,7 +8,7 @@ import React, { useContext, useState, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { useKibana, useUiSetting } from '../../../../../../../src/plugins/kibana_react/public'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; import { ComponentProps } from '../../route_init'; import { useCharts } from '../../hooks/use_charts'; // @ts-ignore diff --git a/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx b/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx index b05bd783b2ff2..26072f53f4752 100644 --- a/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx @@ -18,7 +18,8 @@ import { Legacy } from '../../../legacy_shims'; import { Enabler } from './enabler'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; import { initSetupModeState } from '../../setup_mode/setup_mode'; -import { GlobalStateContext } from '../../global_state_context'; +import { GlobalStateContext } from '../../contexts/global_state_context'; +import { useRequestErrorHandler } from '../../hooks/use_request_error_handler'; const CODE_PATHS = [CODE_PATH_LICENSE]; @@ -77,7 +78,8 @@ export const NoDataPage = () => { ]); const globalState = useContext(GlobalStateContext); - initSetupModeState(globalState, services.http); + const handleRequestError = useRequestErrorHandler(); + initSetupModeState(globalState, services.http, handleRequestError); // From x-pack/plugins/monitoring/public/views/no_data/model_updater.js const updateModel = useCallback( diff --git a/x-pack/plugins/monitoring/public/application/pages/page_template.tsx b/x-pack/plugins/monitoring/public/application/pages/page_template.tsx index 927c464552087..5c030814d9cdf 100644 --- a/x-pack/plugins/monitoring/public/application/pages/page_template.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/page_template.tsx @@ -6,8 +6,9 @@ */ import { EuiTab, EuiTabs } from '@elastic/eui'; -import React, { useContext, useState, useEffect } from 'react'; +import React, { useContext, useState, useEffect, useCallback } from 'react'; import { useHistory } from 'react-router-dom'; +import { IHttpFetchError } from 'kibana/public'; import { useTitle } from '../hooks/use_title'; import { MonitoringToolbar } from '../../components/shared/toolbar'; import { MonitoringTimeContainer } from '../hooks/use_monitoring_time'; @@ -18,6 +19,9 @@ import { updateSetupModeData, } from '../setup_mode/setup_mode'; import { SetupModeFeature } from '../../../common/enums'; +import { AlertsDropdown } from '../../alerts/alerts_dropdown'; +import { ActionMenu } from '../../components/action_menu'; +import { useRequestErrorHandler } from '../hooks/use_request_error_handler'; export interface TabMenuItem { id: string; @@ -46,34 +50,52 @@ export const PageTemplate: React.FC = ({ const { currentTimerange } = useContext(MonitoringTimeContainer.Context); const [loaded, setLoaded] = useState(false); const history = useHistory(); + const [hasError, setHasError] = useState(false); + const handleRequestError = useRequestErrorHandler(); + + const getPageDataResponseHandler = useCallback( + (result: any) => { + setHasError(false); + return result; + }, + [setHasError] + ); useEffect(() => { getPageData?.() - .catch((err) => { - // TODO: handle errors + .then(getPageDataResponseHandler) + .catch((err: IHttpFetchError) => { + handleRequestError(err); + setHasError(true); }) .finally(() => { setLoaded(true); }); - }, [getPageData, currentTimerange]); + }, [getPageData, currentTimerange, getPageDataResponseHandler, handleRequestError]); const onRefresh = () => { - const requests = [getPageData?.()]; + getPageData?.().then(getPageDataResponseHandler).catch(handleRequestError); + if (isSetupModeFeatureEnabled(SetupModeFeature.MetricbeatMigration)) { - requests.push(updateSetupModeData()); + updateSetupModeData(); } - - Promise.allSettled(requests).then((results) => { - // TODO: handle errors - }); }; const createHref = (route: string) => history.createHref({ pathname: route }); const isTabSelected = (route: string) => history.location.pathname === route; + const renderContent = () => { + if (hasError) return null; + if (getPageData && !loaded) return ; + return children; + }; + return (
+ + + {tabs && ( @@ -93,7 +115,7 @@ export const PageTemplate: React.FC = ({ })} )} -
{!getPageData ? children : loaded ? children : }
+
{renderContent()}
); }; diff --git a/x-pack/plugins/monitoring/public/application/route_init.tsx b/x-pack/plugins/monitoring/public/application/route_init.tsx index 8a9a906dbd563..8a11df3de50ae 100644 --- a/x-pack/plugins/monitoring/public/application/route_init.tsx +++ b/x-pack/plugins/monitoring/public/application/route_init.tsx @@ -7,7 +7,7 @@ import React, { useContext } from 'react'; import { Route, Redirect, useLocation } from 'react-router-dom'; import { useClusters } from './hooks/use_clusters'; -import { GlobalStateContext } from './global_state_context'; +import { GlobalStateContext } from './contexts/global_state_context'; import { getClusterFromClusters } from '../lib/get_cluster_from_clusters'; export interface ComponentProps { diff --git a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode.tsx b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode.tsx index 70932e5177337..bfdf96ef5b2c1 100644 --- a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode.tsx +++ b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode.tsx @@ -9,13 +9,13 @@ import React from 'react'; import { render } from 'react-dom'; import { get, includes } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { HttpStart } from 'kibana/public'; +import { HttpStart, IHttpFetchError } from 'kibana/public'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { Legacy } from '../../legacy_shims'; import { SetupModeEnterButton } from '../../components/setup_mode/enter_button'; import { SetupModeFeature } from '../../../common/enums'; import { ISetupModeContext } from '../../components/setup_mode/setup_mode_context'; -import { State as GlobalState } from '../../application/global_state_context'; +import { State as GlobalState } from '../contexts/global_state_context'; function isOnPage(hash: string) { return includes(window.location.hash, hash); @@ -23,6 +23,7 @@ function isOnPage(hash: string) { let globalState: GlobalState; let httpService: HttpStart; +let errorHandler: (error: IHttpFetchError) => void; interface ISetupModeState { enabled: boolean; @@ -65,8 +66,8 @@ export const fetchCollectionData = async (uuid?: string, fetchWithoutClusterUuid }); return response; } catch (err) { - // TODO: handle errors - throw new Error(err); + errorHandler(err); + throw err; } }; @@ -122,8 +123,8 @@ export const disableElasticsearchInternalCollection = async () => { const response = await httpService.post(url); return response; } catch (err) { - // TODO: handle errors - throw new Error(err); + errorHandler(err); + throw err; } }; @@ -161,10 +162,12 @@ export const setSetupModeMenuItem = () => { export const initSetupModeState = async ( state: GlobalState, http: HttpStart, + handleErrors: (error: IHttpFetchError) => void, callback?: () => void ) => { globalState = state; httpService = http; + errorHandler = handleErrors; if (callback) { setupModeState.callback = callback; } diff --git a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.js b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.js index 337dacd4ecae9..a9ee2464cd423 100644 --- a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.js +++ b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.js @@ -27,8 +27,9 @@ import { import { findNewUuid } from '../../components/renderers/lib/find_new_uuid'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { GlobalStateContext } from '../../application/global_state_context'; +import { GlobalStateContext } from '../../application/contexts/global_state_context'; import { withKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { useRequestErrorHandler } from '../hooks/use_request_error_handler'; class WrappedSetupModeRenderer extends React.Component { globalState; @@ -42,8 +43,8 @@ class WrappedSetupModeRenderer extends React.Component { UNSAFE_componentWillMount() { this.globalState = this.context; - const { kibana } = this.props; - initSetupModeState(this.globalState, kibana.services.http, (_oldData) => { + const { kibana, onHttpError } = this.props; + initSetupModeState(this.globalState, kibana.services.http, onHttpError, (_oldData) => { const newState = { renderState: true }; const { productName } = this.props; @@ -213,5 +214,12 @@ class WrappedSetupModeRenderer extends React.Component { } } +function withErrorHandler(Component) { + return function WrappedComponent(props) { + const handleRequestError = useRequestErrorHandler(); + return ; + }; +} + WrappedSetupModeRenderer.contextType = GlobalStateContext; -export const SetupModeRenderer = withKibana(WrappedSetupModeRenderer); +export const SetupModeRenderer = withKibana(withErrorHandler(WrappedSetupModeRenderer)); diff --git a/x-pack/plugins/monitoring/public/components/action_menu/index.tsx b/x-pack/plugins/monitoring/public/components/action_menu/index.tsx new file mode 100644 index 0000000000000..1348ac170395e --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/action_menu/index.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useContext, useEffect } from 'react'; +import { + KibanaContextProvider, + toMountPoint, + useKibana, +} from '../../../../../../src/plugins/kibana_react/public'; +import { HeaderActionMenuContext } from '../../application/contexts/header_action_menu_context'; + +export const ActionMenu: React.FC<{}> = ({ children }) => { + const { services } = useKibana(); + const { setHeaderActionMenu } = useContext(HeaderActionMenuContext); + useEffect(() => { + if (setHeaderActionMenu) { + setHeaderActionMenu((element) => { + const mount = toMountPoint( + {children} + ); + return mount(element); + }); + return () => { + setHeaderActionMenu(undefined); + }; + } + }, [children, setHeaderActionMenu, services]); + + return null; +}; diff --git a/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx b/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx index 32bbdd6ecbeda..6a1ed1dd16f48 100644 --- a/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx +++ b/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx @@ -14,7 +14,7 @@ import { } from '@elastic/eui'; import React, { useContext, useCallback } from 'react'; import { MonitoringTimeContainer } from '../../application/hooks/use_monitoring_time'; -import { GlobalStateContext } from '../../application/global_state_context'; +import { GlobalStateContext } from '../../application/contexts/global_state_context'; import { Legacy } from '../../legacy_shims'; interface MonitoringToolbarProps { diff --git a/x-pack/plugins/monitoring/public/lib/fetch_alerts.ts b/x-pack/plugins/monitoring/public/lib/fetch_alerts.ts new file mode 100644 index 0000000000000..c0ce7ed260889 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/fetch_alerts.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { HttpHandler } from 'kibana/public'; +import { CommonAlertFilter } from '../../common/types/alerts'; +import { AlertsByName } from '../alerts/types'; + +interface FetchAlertsParams { + alertTypeIds?: string[]; + filters?: CommonAlertFilter[]; + timeRange: { min: number; max: number }; + clusterUuid: string; + fetch: HttpHandler; +} + +export const fetchAlerts = async ({ + alertTypeIds, + filters, + timeRange, + clusterUuid, + fetch, +}: FetchAlertsParams): Promise => { + const url = `../api/monitoring/v1/alert/${clusterUuid}/status`; + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify({ + alertTypeIds, + filters, + timeRange, + }), + }); + return response as unknown as AlertsByName; +}; From badc77828ec21960708531e4470952ae2d051040 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Mon, 11 Oct 2021 12:55:06 -0400 Subject: [PATCH 12/73] [Cases][Observability] Do not sync alerts status with case status (#114318) * set sync status according to disable alerts * Adding test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/create/form_context.test.tsx | 23 +++++++++++++++++++ .../public/components/create/form_context.tsx | 10 +++++++- .../cases/public/components/create/index.tsx | 2 ++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/create/form_context.test.tsx b/x-pack/plugins/cases/public/components/create/form_context.test.tsx index b988f13ee34ce..b55542499fbe4 100644 --- a/x-pack/plugins/cases/public/components/create/form_context.test.tsx +++ b/x-pack/plugins/cases/public/components/create/form_context.test.tsx @@ -239,6 +239,29 @@ describe('Create case', () => { ); }); + it('should set sync alerts to false when the sync setting is passed in as false and alerts are disabled', async () => { + useConnectorsMock.mockReturnValue({ + ...sampleConnectorData, + connectors: connectorsMock, + }); + + const wrapper = mount( + + + + + + + ); + + fillForm(wrapper); + wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); + + await waitFor(() => + expect(postCase).toBeCalledWith({ ...sampleData, settings: { syncAlerts: false } }) + ); + }); + it('it should select the default connector set in the configuration', async () => { useCaseConfigureMock.mockImplementation(() => ({ ...useCaseConfigureResponse, diff --git a/x-pack/plugins/cases/public/components/create/form_context.tsx b/x-pack/plugins/cases/public/components/create/form_context.tsx index f59e1822c70be..03d8ec56fb0ae 100644 --- a/x-pack/plugins/cases/public/components/create/form_context.tsx +++ b/x-pack/plugins/cases/public/components/create/form_context.tsx @@ -34,6 +34,7 @@ interface Props { children?: JSX.Element | JSX.Element[]; hideConnectorServiceNowSir?: boolean; onSuccess?: (theCase: Case) => Promise; + syncAlertsDefaultValue?: boolean; } export const FormContext: React.FC = ({ @@ -42,6 +43,7 @@ export const FormContext: React.FC = ({ children, hideConnectorServiceNowSir, onSuccess, + syncAlertsDefaultValue = true, }) => { const { connectors, loading: isLoadingConnectors } = useConnectors(); const owner = useOwnerContext(); @@ -51,7 +53,12 @@ export const FormContext: React.FC = ({ const submitCase = useCallback( async ( - { connectorId: dataConnectorId, fields, syncAlerts = true, ...dataWithoutConnectorId }, + { + connectorId: dataConnectorId, + fields, + syncAlerts = syncAlertsDefaultValue, + ...dataWithoutConnectorId + }, isValid ) => { if (isValid) { @@ -94,6 +101,7 @@ export const FormContext: React.FC = ({ onSuccess, postComment, pushCaseToExternalService, + syncAlertsDefaultValue, ] ); diff --git a/x-pack/plugins/cases/public/components/create/index.tsx b/x-pack/plugins/cases/public/components/create/index.tsx index 7f8b8f664529e..d3eaba1ea0bc4 100644 --- a/x-pack/plugins/cases/public/components/create/index.tsx +++ b/x-pack/plugins/cases/public/components/create/index.tsx @@ -58,6 +58,8 @@ const CreateCaseComponent = ({ caseType={caseType} hideConnectorServiceNowSir={hideConnectorServiceNowSir} onSuccess={onSuccess} + // if we are disabling alerts, then we should not sync alerts + syncAlertsDefaultValue={!disableAlerts} > Date: Mon, 11 Oct 2021 12:30:14 -0500 Subject: [PATCH 13/73] [monitoring] fixup types (#114342) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/hooks/use_table.ts | 8 +--- .../setup_mode/setup_mode_renderer.d.ts | 3 +- .../public/components/apm/status_icon.js | 6 +-- .../components/cluster/overview/index.d.ts | 11 ++++- .../elasticsearch/cluster_status/index.d.ts | 9 +++- .../components/elasticsearch/index.d.ts | 12 ------ .../elasticsearch/{index.js => index.ts} | 0 .../indices/{index.js => index.ts} | 0 .../elasticsearch/indices/indices.d.ts | 20 +++++++++ .../ml_job_listing/status_icon.tsx | 10 ++--- .../elasticsearch/ml_jobs/ml_jobs.tsx | 2 +- .../elasticsearch/node/{index.js => index.ts} | 0 .../components/elasticsearch/node/node.d.ts | 20 +++++++++ .../elasticsearch/node/node_react.d.ts | 19 +++++++++ .../node/status_icon.d.ts} | 8 +++- .../elasticsearch/node/status_icon.js | 4 +- .../nodes/{index.js => index.ts} | 0 .../components/elasticsearch/nodes/nodes.d.ts | 15 +++++++ .../overview/{index.js => index.ts} | 0 .../elasticsearch/overview/overview.d.ts | 18 ++++++++ .../transformers/nodes_by_indices.d.ts | 2 +- .../components/elasticsearch/status_icon.js | 4 +- .../public/components/{index.js => index.ts} | 0 .../components/kibana/instances/instances.tsx | 5 +-- .../public/components/kibana/status_icon.js | 6 +-- .../license/{index.js => index.tsx} | 35 ++++++++++++---- .../components/no_data/{index.js => index.ts} | 0 .../{index.d.ts => no_data/no_data.d.ts} | 5 ++- .../page_loading/{index.js => index.tsx} | 12 ++++-- .../{formatting.js => formatting.ts} | 4 +- .../public/components/status_icon/index.js | 28 ------------- .../public/components/status_icon/index.tsx | 42 +++++++++++++++++++ .../summary_status/summary_status.js | 2 +- .../table/{eui_table.js => eui_table.tsx} | 16 +++---- .../table/eui_table_ssp.d.ts} | 8 ++-- .../public/components/table/index.d.ts | 10 ----- .../components/table/{index.js => index.ts} | 0 .../table/{storage.js => storage.ts} | 29 +++++++++---- ...usters.js => get_cluster_from_clusters.ts} | 13 ++++-- 39 files changed, 267 insertions(+), 119 deletions(-) delete mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts rename x-pack/plugins/monitoring/public/components/elasticsearch/{index.js => index.ts} (100%) rename x-pack/plugins/monitoring/public/components/elasticsearch/indices/{index.js => index.ts} (100%) create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.d.ts rename x-pack/plugins/monitoring/public/components/elasticsearch/node/{index.js => index.ts} (100%) create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/node/node.d.ts create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/node/node_react.d.ts rename x-pack/plugins/monitoring/public/components/{status_icon/index.d.ts => elasticsearch/node/status_icon.d.ts} (56%) rename x-pack/plugins/monitoring/public/components/elasticsearch/nodes/{index.js => index.ts} (100%) create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.d.ts rename x-pack/plugins/monitoring/public/components/elasticsearch/overview/{index.js => index.ts} (100%) create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.d.ts rename x-pack/plugins/monitoring/public/components/{index.js => index.ts} (100%) rename x-pack/plugins/monitoring/public/components/license/{index.js => index.tsx} (86%) rename x-pack/plugins/monitoring/public/components/no_data/{index.js => index.ts} (100%) rename x-pack/plugins/monitoring/public/components/{index.d.ts => no_data/no_data.d.ts} (71%) rename x-pack/plugins/monitoring/public/components/page_loading/{index.js => index.tsx} (89%) rename x-pack/plugins/monitoring/public/components/setup_mode/{formatting.js => formatting.ts} (93%) delete mode 100644 x-pack/plugins/monitoring/public/components/status_icon/index.js create mode 100644 x-pack/plugins/monitoring/public/components/status_icon/index.tsx rename x-pack/plugins/monitoring/public/components/table/{eui_table.js => eui_table.tsx} (88%) rename x-pack/plugins/monitoring/public/{lib/get_cluster_from_clusters.d.ts => components/table/eui_table_ssp.d.ts} (68%) delete mode 100644 x-pack/plugins/monitoring/public/components/table/index.d.ts rename x-pack/plugins/monitoring/public/components/table/{index.js => index.ts} (100%) rename x-pack/plugins/monitoring/public/components/table/{storage.js => storage.ts} (71%) rename x-pack/plugins/monitoring/public/lib/{get_cluster_from_clusters.js => get_cluster_from_clusters.ts} (74%) diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_table.ts b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts index 2e6018ec89809..45d1f717f5d49 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_table.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts @@ -6,6 +6,7 @@ */ import { useState, useCallback } from 'react'; +import { EuiTableSortingType } from '@elastic/eui'; import { euiTableStorageGetter, euiTableStorageSetter } from '../../components/table'; import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; @@ -23,12 +24,7 @@ interface Page { index: number; } -interface Sorting { - sort: { - field: string; - direction: string; - }; -} +type Sorting = EuiTableSortingType; const PAGE_SIZE_OPTIONS = [5, 10, 20, 50]; diff --git a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.d.ts b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.d.ts index 48e8ee13059c0..c0eda496a09b2 100644 --- a/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.d.ts +++ b/x-pack/plugins/monitoring/public/application/setup_mode/setup_mode_renderer.d.ts @@ -5,8 +5,9 @@ * 2.0. */ -export const SetupModeRenderer: FunctionComponent; +import { FunctionComponent } from 'react'; +export const SetupModeRenderer: FunctionComponent>; export interface SetupModeProps { setupMode: any; flyoutComponent: any; diff --git a/x-pack/plugins/monitoring/public/components/apm/status_icon.js b/x-pack/plugins/monitoring/public/components/apm/status_icon.js index f27bcefc20bcb..14a51313e4aa7 100644 --- a/x-pack/plugins/monitoring/public/components/apm/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/apm/status_icon.js @@ -6,17 +6,17 @@ */ import React from 'react'; -import { StatusIcon } from '../../components/status_icon'; +import { StatusIcon, STATUS_ICON_TYPES } from '../../components/status_icon'; import { i18n } from '@kbn/i18n'; export function ApmStatusIcon({ status, availability = true }) { const type = (() => { if (!availability) { - return StatusIcon.TYPES.GRAY; + return STATUS_ICON_TYPES.GRAY; } const statusKey = status.toUpperCase(); - return StatusIcon.TYPES[statusKey] || StatusIcon.TYPES.YELLOW; + return STATUS_ICON_TYPES[statusKey] || STATUS_ICON_TYPES.YELLOW; })(); return ( diff --git a/x-pack/plugins/monitoring/public/components/cluster/overview/index.d.ts b/x-pack/plugins/monitoring/public/components/cluster/overview/index.d.ts index 2cfd37e8e27eb..3dc7121446a7a 100644 --- a/x-pack/plugins/monitoring/public/components/cluster/overview/index.d.ts +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/index.d.ts @@ -5,4 +5,13 @@ * 2.0. */ -export const Overview: FunctionComponent; +import { FunctionComponent } from 'react'; + +export const Overview: FunctionComponent; + +export interface OverviewProps { + cluster: unknown; + setupMode: unknown; + showLicenseExpiration: boolean; + alerts: unknown; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.d.ts index b7196d25d1791..4f314101ed299 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.d.ts +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.d.ts @@ -5,4 +5,11 @@ * 2.0. */ -export const ClusterStatus: FunctionComponent; +import { FunctionComponent } from 'react'; + +export const ClusterStatus: FunctionComponent; + +export interface ClusterStatusProps { + stats: unknown; + alerts?: unknown; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts deleted file mode 100644 index 09f6c1085cfa3..0000000000000 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts +++ /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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const ElasticsearchOverview: FunctionComponent; -export const ElasticsearchNodes: FunctionComponent; -export const ElasticsearchIndices: FunctionComponent; -export const ElasticsearchMLJobs: FunctionComponent; -export const NodeReact: FunctionComponent; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/elasticsearch/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/index.ts diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.ts diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.d.ts new file mode 100644 index 0000000000000..2b8ea60b651a6 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.d.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FunctionComponent } from 'react'; + +export const ElasticsearchIndices: FunctionComponent; +export interface ElasticsearchIndicesProps { + clusterStatus: unknown; + indices: unknown; + sorting: unknown; + pagination: unknown; + onTableChange: unknown; + toggleShowSystemIndices: unknown; + showSystemIndices: unknown; + alerts: unknown; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.tsx b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.tsx index d5c65aecdec21..a45c8316d1aa3 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.tsx +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.tsx @@ -7,22 +7,22 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { StatusIcon } from '../../status_icon'; +import { StatusIcon, STATUS_ICON_TYPES } from '../../status_icon'; export function MachineLearningJobStatusIcon({ status }: { status: string }) { const type = (() => { const statusKey = status.toUpperCase(); if (statusKey === 'OPENED') { - return StatusIcon.TYPES.GREEN; + return STATUS_ICON_TYPES.GREEN; } else if (statusKey === 'CLOSED') { - return StatusIcon.TYPES.GRAY; + return STATUS_ICON_TYPES.GRAY; } else if (statusKey === 'FAILED') { - return StatusIcon.TYPES.RED; + return STATUS_ICON_TYPES.RED; } // basically a "changing" state like OPENING or CLOSING - return StatusIcon.TYPES.YELLOW; + return STATUS_ICON_TYPES.YELLOW; })(); return ( diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/ml_jobs/ml_jobs.tsx b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_jobs/ml_jobs.tsx index 635f9ecd1e10a..dba9c40fabb2b 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/ml_jobs/ml_jobs.tsx +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_jobs/ml_jobs.tsx @@ -31,7 +31,7 @@ import { ClusterStatus } from '../cluster_status'; interface Props { clusterStatus: boolean; jobs: MLJobs; - onTableChange: () => void; + onTableChange: (props: any) => void; sorting: EuiTableSortingType; pagination: Pagination; } diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/elasticsearch/node/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/index.ts diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.d.ts new file mode 100644 index 0000000000000..9d7a062e942bb --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.d.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FunctionComponent } from 'react'; + +export const Node: FunctionComponent; +export interface NodeProps { + nodeSummary: unknown; + metrics: unknown; + logs: unknown; + alerts: unknown; + nodeId: unknown; + clusterUuid: unknown; + scope: unknown; + [key: string]: any; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/node_react.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node_react.d.ts new file mode 100644 index 0000000000000..e0c4f6b301fdb --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node_react.d.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FunctionComponent } from 'react'; + +export const NodeReact: FunctionComponent; +export interface NodeReactProps { + nodeSummary: unknown; + metrics: unknown; + logs: unknown; + alerts: unknown; + nodeId: unknown; + clusterUuid: unknown; + [key: string]: any; +} diff --git a/x-pack/plugins/monitoring/public/components/status_icon/index.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.d.ts similarity index 56% rename from x-pack/plugins/monitoring/public/components/status_icon/index.d.ts rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.d.ts index 147c2821e3a2a..dfa07524619c9 100644 --- a/x-pack/plugins/monitoring/public/components/status_icon/index.d.ts +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.d.ts @@ -5,4 +5,10 @@ * 2.0. */ -export const StatusIcon: FunctionComponent; +import { FunctionComponent } from 'react'; + +export const NodeStatusIcon: FunctionComponent; +export interface NodeStatusIconProps { + isOnline: boolean; + status: string; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js index 7bfffc7b73954..9905a6c3573f7 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js @@ -6,11 +6,11 @@ */ import React from 'react'; -import { StatusIcon } from '../../status_icon'; +import { StatusIcon, STATUS_ICON_TYPES } from '../../status_icon'; import { i18n } from '@kbn/i18n'; export function NodeStatusIcon({ isOnline, status }) { - const type = isOnline ? StatusIcon.TYPES.GREEN : StatusIcon.TYPES.GRAY; + const type = isOnline ? STATUS_ICON_TYPES.GREEN : STATUS_ICON_TYPES.GRAY; return ( ; +export interface ElasticsearchNodesProps { + clusterStatus: unknown; + showCgroupMetricsElasticsearch: unknown; + [key: string]: any; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.ts diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.d.ts new file mode 100644 index 0000000000000..d4c893f87cbd2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.d.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FunctionComponent } from 'react'; + +export const ElasticsearchOverview: FunctionComponent; +export interface ElasticsearchOverviewProps { + clusterStatus: unknown; + metrics: unknown; + logs: unknown; + cluster: unknown; + shardActivity: unknown; + [key: string]: any; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.d.ts index d0ec9b85edae7..c430c0ee7b48a 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.d.ts +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.d.ts @@ -5,4 +5,4 @@ * 2.0. */ -export const nodesByIndices: () => (shards, nodes) => any; +export const nodesByIndices: () => (shards: any, nodes: any) => any; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js b/x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js index 7c51a1e89d91e..ec027d71a192d 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js @@ -6,13 +6,13 @@ */ import React from 'react'; -import { StatusIcon } from '../status_icon'; +import { StatusIcon, STATUS_ICON_TYPES } from '../status_icon'; import { i18n } from '@kbn/i18n'; export function ElasticsearchStatusIcon({ status }) { const type = (() => { const statusKey = status.toUpperCase(); - return StatusIcon.TYPES[statusKey] || StatusIcon.TYPES.GRAY; + return STATUS_ICON_TYPES[statusKey] || STATUS_ICON_TYPES.GRAY; })(); return ( diff --git a/x-pack/plugins/monitoring/public/components/index.js b/x-pack/plugins/monitoring/public/components/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/index.js rename to x-pack/plugins/monitoring/public/components/index.ts diff --git a/x-pack/plugins/monitoring/public/components/kibana/instances/instances.tsx b/x-pack/plugins/monitoring/public/components/kibana/instances/instances.tsx index 4e939682b1dba..3766a09f91b80 100644 --- a/x-pack/plugins/monitoring/public/components/kibana/instances/instances.tsx +++ b/x-pack/plugins/monitoring/public/components/kibana/instances/instances.tsx @@ -25,8 +25,7 @@ import { capitalize, get } from 'lodash'; import { ClusterStatus } from '../cluster_status'; // @ts-ignore import { EuiMonitoringTable } from '../../table'; -// @ts-ignore -import { StatusIcon } from '../../status_icon'; +import { STATUS_ICON_TYPES } from '../../status_icon'; // @ts-ignore import { formatMetric, formatNumber } from '../../../lib/format_number'; import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; @@ -205,7 +204,7 @@ export const KibanaInstances: React.FC = (props: Props) => { _instances.push({ kibana: { ...(instance as any).instance.kibana, - status: StatusIcon.TYPES.GRAY, + status: STATUS_ICON_TYPES.GRAY, }, }); } diff --git a/x-pack/plugins/monitoring/public/components/kibana/status_icon.js b/x-pack/plugins/monitoring/public/components/kibana/status_icon.js index e5b501b1e15e7..976b3ff992e3b 100644 --- a/x-pack/plugins/monitoring/public/components/kibana/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/kibana/status_icon.js @@ -6,17 +6,17 @@ */ import React from 'react'; -import { StatusIcon } from '../status_icon'; +import { StatusIcon, STATUS_ICON_TYPES } from '../status_icon'; import { i18n } from '@kbn/i18n'; export function KibanaStatusIcon({ status, availability = true }) { const type = (() => { if (!availability) { - return StatusIcon.TYPES.GRAY; + return STATUS_ICON_TYPES.GRAY; } const statusKey = status.toUpperCase(); - return StatusIcon.TYPES[statusKey] || StatusIcon.TYPES.YELLOW; + return STATUS_ICON_TYPES[statusKey] || STATUS_ICON_TYPES.YELLOW; })(); return ( diff --git a/x-pack/plugins/monitoring/public/components/license/index.js b/x-pack/plugins/monitoring/public/components/license/index.tsx similarity index 86% rename from x-pack/plugins/monitoring/public/components/license/index.js rename to x-pack/plugins/monitoring/public/components/license/index.tsx index ad16663c88ea7..766f0af3bccc8 100644 --- a/x-pack/plugins/monitoring/public/components/license/index.js +++ b/x-pack/plugins/monitoring/public/components/license/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { Fragment } from 'react'; +import React, { Fragment, FunctionComponent } from 'react'; import { EuiPage, EuiPageBody, @@ -27,7 +27,10 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { Legacy } from '../../legacy_shims'; -export const AddLicense = ({ uploadPath }) => { +interface AddLicenseProps { + uploadPath?: string; +} +const AddLicense: FunctionComponent = ({ uploadPath }) => { return ( { ); }; -export class LicenseStatus extends React.PureComponent { +export interface LicenseStatusProps { + isExpired: boolean; + status: string; + type: string; + expiryDate: string | Date; +} + +class LicenseStatus extends React.PureComponent { render() { const { isExpired, status, type, expiryDate } = this.props; const typeTitleCase = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase(); @@ -133,7 +143,15 @@ export class LicenseStatus extends React.PureComponent { } } -const LicenseUpdateInfoForPrimary = ({ isPrimaryCluster, uploadLicensePath }) => { +export interface LicenseUpdateInfoProps { + isPrimaryCluster: boolean; + uploadLicensePath?: string; +} + +const LicenseUpdateInfoForPrimary: FunctionComponent = ({ + isPrimaryCluster, + uploadLicensePath, +}) => { if (!isPrimaryCluster) { return null; } @@ -142,7 +160,9 @@ const LicenseUpdateInfoForPrimary = ({ isPrimaryCluster, uploadLicensePath }) => return ; }; -const LicenseUpdateInfoForRemote = ({ isPrimaryCluster }) => { +const LicenseUpdateInfoForRemote: FunctionComponent = ({ + isPrimaryCluster, +}) => { if (isPrimaryCluster) { return null; } @@ -168,7 +188,8 @@ const LicenseUpdateInfoForRemote = ({ isPrimaryCluster }) => { ); }; -export function License(props) { +export interface LicenseProps extends LicenseStatusProps, LicenseUpdateInfoProps {} +export const License: FunctionComponent = (props) => { const { status, type, isExpired, expiryDate } = props; const licenseManagement = `${Legacy.shims.getBasePath()}/app/management/stack/license_management`; return ( @@ -199,4 +220,4 @@ export function License(props) {
); -} +}; diff --git a/x-pack/plugins/monitoring/public/components/no_data/index.js b/x-pack/plugins/monitoring/public/components/no_data/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/no_data/index.js rename to x-pack/plugins/monitoring/public/components/no_data/index.ts diff --git a/x-pack/plugins/monitoring/public/components/index.d.ts b/x-pack/plugins/monitoring/public/components/no_data/no_data.d.ts similarity index 71% rename from x-pack/plugins/monitoring/public/components/index.d.ts rename to x-pack/plugins/monitoring/public/components/no_data/no_data.d.ts index fc1a81cc4dba2..b87d326e834af 100644 --- a/x-pack/plugins/monitoring/public/components/index.d.ts +++ b/x-pack/plugins/monitoring/public/components/no_data/no_data.d.ts @@ -5,5 +5,6 @@ * 2.0. */ -export const PageLoading: FunctionComponent; -export const License: FunctionComponent; +import { FunctionComponent } from 'react'; + +export const NoData: FunctionComponent>; diff --git a/x-pack/plugins/monitoring/public/components/page_loading/index.js b/x-pack/plugins/monitoring/public/components/page_loading/index.tsx similarity index 89% rename from x-pack/plugins/monitoring/public/components/page_loading/index.js rename to x-pack/plugins/monitoring/public/components/page_loading/index.tsx index fd4aa9d848150..e7535fc3dc859 100644 --- a/x-pack/plugins/monitoring/public/components/page_loading/index.js +++ b/x-pack/plugins/monitoring/public/components/page_loading/index.tsx @@ -48,17 +48,21 @@ function PageLoadingUI() { ); } -function PageLoadingTracking({ pageViewTitle }) { +const PageLoadingTracking: React.FunctionComponent<{ pageViewTitle: string }> = ({ + pageViewTitle, +}) => { const path = pageViewTitle.toLowerCase().replace(/-/g, '').replace(/\s+/g, '_'); useTrackPageview({ app: 'stack_monitoring', path }); useTrackPageview({ app: 'stack_monitoring', path, delay: 15000 }); return ; -} +}; -export function PageLoading({ pageViewTitle }) { +export const PageLoading: React.FunctionComponent<{ pageViewTitle?: string }> = ({ + pageViewTitle, +}) => { if (pageViewTitle) { return ; } return ; -} +}; diff --git a/x-pack/plugins/monitoring/public/components/setup_mode/formatting.js b/x-pack/plugins/monitoring/public/components/setup_mode/formatting.ts similarity index 93% rename from x-pack/plugins/monitoring/public/components/setup_mode/formatting.js rename to x-pack/plugins/monitoring/public/components/setup_mode/formatting.ts index 11e8ca48719fd..06eb029fcc4a0 100644 --- a/x-pack/plugins/monitoring/public/components/setup_mode/formatting.js +++ b/x-pack/plugins/monitoring/public/components/setup_mode/formatting.ts @@ -34,7 +34,7 @@ const SERVER_IDENTIFIER_PLURAL = i18n.translate('xpack.monitoring.setupMode.serv defaultMessage: `servers`, }); -export function formatProductName(productName) { +export function formatProductName(productName: string) { if (productName === APM_SYSTEM_ID) { return productName.toUpperCase(); } @@ -43,7 +43,7 @@ export function formatProductName(productName) { const PRODUCTS_THAT_USE_NODES = [LOGSTASH_SYSTEM_ID, ELASTICSEARCH_SYSTEM_ID]; const PRODUCTS_THAT_USE_INSTANCES = [KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID]; -export function getIdentifier(productName, usePlural = false) { +export function getIdentifier(productName: string, usePlural = false) { if (PRODUCTS_THAT_USE_INSTANCES.includes(productName)) { return usePlural ? INSTANCE_IDENTIFIER_PLURAL : INSTANCE_IDENTIFIER_SINGULAR; } diff --git a/x-pack/plugins/monitoring/public/components/status_icon/index.js b/x-pack/plugins/monitoring/public/components/status_icon/index.js deleted file mode 100644 index bcd4b58d6912f..0000000000000 --- a/x-pack/plugins/monitoring/public/components/status_icon/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiIcon } from '@elastic/eui'; - -export function StatusIcon({ type, label }) { - const typeToIconMap = { - [StatusIcon.TYPES.RED]: 'danger', - [StatusIcon.TYPES.YELLOW]: 'warning', - [StatusIcon.TYPES.GREEN]: 'success', - [StatusIcon.TYPES.GRAY]: 'subdued', - }; - const icon = typeToIconMap[type]; - - return ; -} - -StatusIcon.TYPES = { - RED: 'RED', - YELLOW: 'YELLOW', - GREEN: 'GREEN', - GRAY: 'GRAY', -}; diff --git a/x-pack/plugins/monitoring/public/components/status_icon/index.tsx b/x-pack/plugins/monitoring/public/components/status_icon/index.tsx new file mode 100644 index 0000000000000..59c87866d57d3 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/status_icon/index.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiIcon } from '@elastic/eui'; + +export const STATUS_ICON_TYPES = { + RED: 'RED' as const, + YELLOW: 'YELLOW' as const, + GREEN: 'GREEN' as const, + GRAY: 'GRAY' as const, +}; + +const typeToIconMap = { + [STATUS_ICON_TYPES.RED]: 'danger', + [STATUS_ICON_TYPES.YELLOW]: 'warning', + [STATUS_ICON_TYPES.GREEN]: 'success', + [STATUS_ICON_TYPES.GRAY]: 'subdued', +}; + +export interface StatusIconProps { + type: keyof typeof STATUS_ICON_TYPES; + label: string; +} +export const StatusIcon: React.FunctionComponent = ({ type, label }) => { + const icon = typeToIconMap[type]; + + return ( + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js index 71fcf4e193f20..db4ac9098532b 100644 --- a/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js +++ b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js @@ -9,7 +9,7 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { isEmpty, capitalize } from 'lodash'; import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; -import { StatusIcon } from '../status_icon/index.js'; +import { StatusIcon } from '../status_icon'; import { AlertsStatus } from '../../alerts/status'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; diff --git a/x-pack/plugins/monitoring/public/components/table/eui_table.js b/x-pack/plugins/monitoring/public/components/table/eui_table.tsx similarity index 88% rename from x-pack/plugins/monitoring/public/components/table/eui_table.js rename to x-pack/plugins/monitoring/public/components/table/eui_table.tsx index a702fdc033572..a383fcf1cd666 100644 --- a/x-pack/plugins/monitoring/public/components/table/eui_table.js +++ b/x-pack/plugins/monitoring/public/components/table/eui_table.tsx @@ -5,21 +5,21 @@ * 2.0. */ -import React, { Fragment } from 'react'; +import React, { Fragment, FunctionComponent } from 'react'; import { EuiInMemoryTable, EuiButton, EuiSpacer, EuiSearchBar } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { getIdentifier } from '../setup_mode/formatting'; import { isSetupModeFeatureEnabled } from '../../lib/setup_mode'; import { SetupModeFeature } from '../../../common/enums'; -export function EuiMonitoringTable({ +export const EuiMonitoringTable: FunctionComponent> = ({ rows: items, search = {}, columns: _columns, setupMode, productName, ...props -}) { +}) => { const [hasItems, setHasItem] = React.useState(items.length > 0); if (search.box && !search.box['data-test-subj']) { @@ -32,15 +32,17 @@ export function EuiMonitoringTable({ if (search) { const oldOnChange = search.onChange; - search.onChange = (arg) => { + search.onChange = (arg: any) => { const filteredItems = EuiSearchBar.Query.execute(arg.query, items, props.executeQueryOptions); setHasItem(filteredItems.length > 0); - oldOnChange && oldOnChange(arg); + if (oldOnChange) { + oldOnChange(arg); + } return true; }; } - const columns = _columns.map((column) => { + const columns = _columns.map((column: any) => { if (!('sortable' in column)) { column.sortable = true; } @@ -78,4 +80,4 @@ export function EuiMonitoringTable({ {footerContent} ); -} +}; diff --git a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.d.ts b/x-pack/plugins/monitoring/public/components/table/eui_table_ssp.d.ts similarity index 68% rename from x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.d.ts rename to x-pack/plugins/monitoring/public/components/table/eui_table_ssp.d.ts index 5a310c977efae..bdc8199b3c57c 100644 --- a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.d.ts +++ b/x-pack/plugins/monitoring/public/components/table/eui_table_ssp.d.ts @@ -5,8 +5,6 @@ * 2.0. */ -export const getClusterFromClusters: ( - clusters: any, - globalState: State, - unsetGlobalState: boolean -) => any; +import { FunctionComponent } from 'react'; + +export const EuiMonitoringSSPTable: FunctionComponent>; diff --git a/x-pack/plugins/monitoring/public/components/table/index.d.ts b/x-pack/plugins/monitoring/public/components/table/index.d.ts deleted file mode 100644 index 23406ba9e3a5e..0000000000000 --- a/x-pack/plugins/monitoring/public/components/table/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const euiTableStorageGetter: (string) => any; -export const euiTableStorageSetter: (string) => any; -export const EuiMonitoringTable: FunctionComponent; diff --git a/x-pack/plugins/monitoring/public/components/table/index.js b/x-pack/plugins/monitoring/public/components/table/index.ts similarity index 100% rename from x-pack/plugins/monitoring/public/components/table/index.js rename to x-pack/plugins/monitoring/public/components/table/index.ts diff --git a/x-pack/plugins/monitoring/public/components/table/storage.js b/x-pack/plugins/monitoring/public/components/table/storage.ts similarity index 71% rename from x-pack/plugins/monitoring/public/components/table/storage.js rename to x-pack/plugins/monitoring/public/components/table/storage.ts index b9694dc5db420..411bd09872858 100644 --- a/x-pack/plugins/monitoring/public/components/table/storage.js +++ b/x-pack/plugins/monitoring/public/components/table/storage.ts @@ -8,9 +8,22 @@ import { set } from '@elastic/safer-lodash-set'; import { get } from 'lodash'; import { STORAGE_KEY } from '../../../common/constants'; +import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; -export const tableStorageGetter = (keyPrefix) => { - return (storage) => { +interface TableValues { + filterText: any; + pageIndex: any; + sortKey: any; + sortOrder: any; +} + +interface EuiTableValues { + sort: any; + page: any; +} + +export const tableStorageGetter = (keyPrefix: string) => { + return (storage: Storage): TableValues => { const localStorageData = storage.get(STORAGE_KEY) || {}; const filterText = get(localStorageData, [keyPrefix, 'filterText']); const pageIndex = get(localStorageData, [keyPrefix, 'pageIndex']); @@ -21,8 +34,8 @@ export const tableStorageGetter = (keyPrefix) => { }; }; -export const tableStorageSetter = (keyPrefix) => { - return (storage, { filterText, pageIndex, sortKey, sortOrder }) => { +export const tableStorageSetter = (keyPrefix: string) => { + return (storage: Storage, { filterText, pageIndex, sortKey, sortOrder }: TableValues) => { const localStorageData = storage.get(STORAGE_KEY) || {}; set(localStorageData, [keyPrefix, 'filterText'], filterText || undefined); // don`t store empty data @@ -36,8 +49,8 @@ export const tableStorageSetter = (keyPrefix) => { }; }; -export const euiTableStorageGetter = (keyPrefix) => { - return (storage) => { +export const euiTableStorageGetter = (keyPrefix: string) => { + return (storage: Storage): EuiTableValues => { const localStorageData = storage.get(STORAGE_KEY) || {}; const sort = get(localStorageData, [keyPrefix, 'sort']); const page = get(localStorageData, [keyPrefix, 'page']); @@ -46,8 +59,8 @@ export const euiTableStorageGetter = (keyPrefix) => { }; }; -export const euiTableStorageSetter = (keyPrefix) => { - return (storage, { sort, page }) => { +export const euiTableStorageSetter = (keyPrefix: string) => { + return (storage: Storage, { sort, page }: EuiTableValues) => { const localStorageData = storage.get(STORAGE_KEY) || {}; set(localStorageData, [keyPrefix, 'sort'], sort || undefined); // don`t store empty data diff --git a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.js b/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts similarity index 74% rename from x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.js rename to x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts index 94bd39aa769fd..837f59aaf7c20 100644 --- a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.js +++ b/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts @@ -6,15 +6,20 @@ */ import { find, first } from 'lodash'; +import { State } from '../application/global_state_context'; -export function getClusterFromClusters(clusters, globalState, unsetGlobalState = false) { +export function getClusterFromClusters( + clusters: any, + globalState: State, + unsetGlobalState = false +) { const cluster = (() => { const existingCurrent = find(clusters, { cluster_uuid: globalState.cluster_uuid }); if (existingCurrent) { return existingCurrent; } - const firstCluster = first(clusters); + const firstCluster: any = first(clusters); if (firstCluster && firstCluster.cluster_uuid) { return firstCluster; } @@ -25,7 +30,9 @@ export function getClusterFromClusters(clusters, globalState, unsetGlobalState = if (cluster && cluster.license) { globalState.cluster_uuid = unsetGlobalState ? undefined : cluster.cluster_uuid; globalState.ccs = unsetGlobalState ? undefined : cluster.ccs; - globalState.save(); + if (globalState.save) { + globalState.save(); + } return cluster; } From 50b3602d7f5eb046fe57e68c5718ab9c2169def5 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 11 Oct 2021 17:41:49 +0000 Subject: [PATCH 14/73] fix import --- .../plugins/monitoring/public/lib/get_cluster_from_clusters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts b/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts index 837f59aaf7c20..93d0c5a6f790e 100644 --- a/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts +++ b/x-pack/plugins/monitoring/public/lib/get_cluster_from_clusters.ts @@ -6,7 +6,7 @@ */ import { find, first } from 'lodash'; -import { State } from '../application/global_state_context'; +import { State } from '../application/contexts/global_state_context'; export function getClusterFromClusters( clusters: any, From 9d498b962c88680c306722d172ad1841c7ddea27 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Mon, 11 Oct 2021 12:55:06 -0500 Subject: [PATCH 15/73] [APM] Disabling apm e2e test (#114544) [skip-ci] APM Cypress tests are again failing on PRs. Disable temporarily. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- vars/tasks.groovy | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vars/tasks.groovy b/vars/tasks.groovy index 1842e278282b1..5a015bddc8fbc 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -146,13 +146,14 @@ def functionalXpack(Map params = [:]) { } } - whenChanged([ - 'x-pack/plugins/apm/', - ]) { - if (githubPr.isPr()) { - task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) - } - } + //temporarily disable apm e2e test since it's breaking. + // whenChanged([ + // 'x-pack/plugins/apm/', + // ]) { + // if (githubPr.isPr()) { + // task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) + // } + // } whenChanged([ 'x-pack/plugins/uptime/', From e32dd1c493b747345b4d1103d14f61898ad5ccfe Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Mon, 11 Oct 2021 14:19:28 -0400 Subject: [PATCH 16/73] [Alerting] Allow rule types to specify a default and minimum interval (#113650) * WIP * Remove test defaults * Fix types * Add tests * Add missing files * Fix issue with using default interval after user manually changed it * PR feedback * Fix types * Remove debug --- x-pack/plugins/alerting/README.md | 2 + x-pack/plugins/alerting/common/alert_type.ts | 2 + .../alerting/server/routes/rule_types.test.ts | 6 + .../alerting/server/routes/rule_types.ts | 4 + .../server/rule_type_registry.test.ts | 57 +++- .../alerting/server/rule_type_registry.ts | 44 +++ .../server/rules_client/rules_client.ts | 22 ++ .../server/rules_client/tests/create.test.ts | 26 ++ .../server/rules_client/tests/update.test.ts | 46 +++ x-pack/plugins/alerting/server/types.ts | 2 + .../public/application/constants/index.ts | 2 + .../components/alert_details.tsx | 1 + .../sections/alert_form/alert_add.test.tsx | 24 +- .../sections/alert_form/alert_add.tsx | 57 +++- .../sections/alert_form/alert_edit.test.tsx | 34 ++- .../sections/alert_form/alert_edit.tsx | 33 +- .../sections/alert_form/alert_errors.test.tsx | 284 ++++++++++++++++++ .../sections/alert_form/alert_errors.ts | 132 ++++++++ .../sections/alert_form/alert_form.tsx | 149 +++------ .../alerts_list/components/alerts_list.tsx | 25 +- .../triggers_actions_ui/public/types.ts | 6 +- 21 files changed, 822 insertions(+), 136 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.test.tsx create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.ts diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 58d2ca35dea7e..343960aee9dfb 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -122,6 +122,8 @@ The following table describes the properties of the `options` object. |useSavedObjectReferences.extractReferences|(Optional) When developing a rule type, you can choose to implement hooks for extracting saved object references from rule parameters. This hook will be invoked when a rule is created or updated. Implementing this hook is optional, but if an extract hook is implemented, an inject hook must also be implemented.|Function |useSavedObjectReferences.injectReferences|(Optional) When developing a rule type, you can choose to implement hooks for injecting saved object references into rule parameters. This hook will be invoked when a rule is retrieved (get or find). Implementing this hook is optional, but if an inject hook is implemented, an extract hook must also be implemented.|Function |isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean| +|defaultScheduleInterval|The default interval that will show up in the UI when creating a rule of this rule type.|boolean| +|minimumScheduleInterval|The minimum interval that will be allowed for all rules of this rule type.|boolean| ### Executor diff --git a/x-pack/plugins/alerting/common/alert_type.ts b/x-pack/plugins/alerting/common/alert_type.ts index e56034a4c41f8..d71540b4418e8 100644 --- a/x-pack/plugins/alerting/common/alert_type.ts +++ b/x-pack/plugins/alerting/common/alert_type.ts @@ -21,6 +21,8 @@ export interface AlertType< producer: string; minimumLicenseRequired: LicenseType; isExportable: boolean; + defaultScheduleInterval?: string; + minimumScheduleInterval?: string; } export interface ActionGroup { diff --git a/x-pack/plugins/alerting/server/routes/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule_types.test.ts index 2e8f43508a969..e4247c9de6cad 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.test.ts @@ -57,6 +57,8 @@ describe('ruleTypesRoute', () => { }, producer: 'test', enabledInLicense: true, + minimumScheduleInterval: '1m', + defaultScheduleInterval: '10m', } as RegistryAlertTypeWithAuth, ]; const expectedResult: Array> = [ @@ -70,7 +72,9 @@ describe('ruleTypesRoute', () => { }, ], default_action_group_id: 'default', + default_schedule_interval: '10m', minimum_license_required: 'basic', + minimum_schedule_interval: '1m', is_exportable: true, recovery_action_group: RecoveredActionGroup, authorized_consumers: {}, @@ -102,10 +106,12 @@ describe('ruleTypesRoute', () => { }, "authorized_consumers": Object {}, "default_action_group_id": "default", + "default_schedule_interval": "10m", "enabled_in_license": true, "id": "1", "is_exportable": true, "minimum_license_required": "basic", + "minimum_schedule_interval": "1m", "name": "name", "producer": "test", "recovery_action_group": Object { diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts index 153ae96ff68ea..72502b25e9aff 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -22,6 +22,8 @@ const rewriteBodyRes: RewriteResponseCase = (result isExportable, actionVariables, authorizedConsumers, + minimumScheduleInterval, + defaultScheduleInterval, ...rest }) => ({ ...rest, @@ -33,6 +35,8 @@ const rewriteBodyRes: RewriteResponseCase = (result is_exportable: isExportable, action_variables: actionVariables, authorized_consumers: authorizedConsumers, + minimum_schedule_interval: minimumScheduleInterval, + default_schedule_interval: defaultScheduleInterval, }) ); }; diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index 1c44e862c261c..beb5f264eb725 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -114,7 +114,7 @@ describe('register()', () => { test('throws if AlertType ruleTaskTimeout is not a valid duration', () => { const alertType: AlertType = { - id: 123 as unknown as string, + id: '123', name: 'Test', actionGroups: [ { @@ -138,6 +138,59 @@ describe('register()', () => { ); }); + test('throws if defaultScheduleInterval isnt valid', () => { + const alertType: AlertType = { + id: '123', + name: 'Test', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + executor: jest.fn(), + producer: 'alerts', + defaultScheduleInterval: 'foobar', + }; + const registry = new RuleTypeRegistry(ruleTypeRegistryParams); + + expect(() => registry.register(alertType)).toThrowError( + new Error( + `Rule type \"123\" has invalid default interval: string is not a valid duration: foobar.` + ) + ); + }); + + test('throws if minimumScheduleInterval isnt valid', () => { + const alertType: AlertType = { + id: '123', + name: 'Test', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + executor: jest.fn(), + producer: 'alerts', + minimumScheduleInterval: 'foobar', + }; + const registry = new RuleTypeRegistry(ruleTypeRegistryParams); + + expect(() => registry.register(alertType)).toThrowError( + new Error( + `Rule type \"123\" has invalid minimum interval: string is not a valid duration: foobar.` + ) + ); + }); + test('throws if RuleType action groups contains reserved group id', () => { const alertType: AlertType = { id: 'test', @@ -465,10 +518,12 @@ describe('list()', () => { "state": Array [], }, "defaultActionGroupId": "testActionGroup", + "defaultScheduleInterval": undefined, "enabledInLicense": false, "id": "test", "isExportable": true, "minimumLicenseRequired": "basic", + "minimumScheduleInterval": undefined, "name": "Test", "producer": "alerts", "recoveryActionGroup": Object { diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index dc72b644b2c7b..db02edf4d19dd 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -48,6 +48,8 @@ export interface RegistryRuleType | 'producer' | 'minimumLicenseRequired' | 'isExportable' + | 'minimumScheduleInterval' + | 'defaultScheduleInterval' > { id: string; enabledInLicense: boolean; @@ -188,6 +190,44 @@ export class RuleTypeRegistry { } alertType.actionVariables = normalizedActionVariables(alertType.actionVariables); + // validate defaultScheduleInterval here + if (alertType.defaultScheduleInterval) { + const invalidDefaultTimeout = validateDurationSchema(alertType.defaultScheduleInterval); + if (invalidDefaultTimeout) { + throw new Error( + i18n.translate( + 'xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutAlertTypeError', + { + defaultMessage: 'Rule type "{id}" has invalid default interval: {errorMessage}.', + values: { + id: alertType.id, + errorMessage: invalidDefaultTimeout, + }, + } + ) + ); + } + } + + // validate minimumScheduleInterval here + if (alertType.minimumScheduleInterval) { + const invalidMinimumTimeout = validateDurationSchema(alertType.minimumScheduleInterval); + if (invalidMinimumTimeout) { + throw new Error( + i18n.translate( + 'xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutAlertTypeError', + { + defaultMessage: 'Rule type "{id}" has invalid minimum interval: {errorMessage}.', + values: { + id: alertType.id, + errorMessage: invalidMinimumTimeout, + }, + } + ) + ); + } + } + const normalizedAlertType = augmentActionGroupsWithReserved< Params, ExtractedParams, @@ -287,6 +327,8 @@ export class RuleTypeRegistry { producer, minimumLicenseRequired, isExportable, + minimumScheduleInterval, + defaultScheduleInterval, }, ]: [string, UntypedNormalizedAlertType]) => ({ id, @@ -298,6 +340,8 @@ export class RuleTypeRegistry { producer, minimumLicenseRequired, isExportable, + minimumScheduleInterval, + defaultScheduleInterval, enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType( id, name, diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 231d19ce9a6f8..2228b5d27910f 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -296,6 +296,17 @@ export class RulesClient { await this.validateActions(ruleType, data.actions); + // Validate intervals, if configured + if (ruleType.minimumScheduleInterval) { + const intervalInMs = parseDuration(data.schedule.interval); + const minimumScheduleIntervalInMs = parseDuration(ruleType.minimumScheduleInterval); + if (intervalInMs < minimumScheduleIntervalInMs) { + throw Boom.badRequest( + `Error updating rule: the interval is less than the minimum interval of ${ruleType.minimumScheduleInterval}` + ); + } + } + // Extract saved object references for this rule const { references, @@ -847,6 +858,17 @@ export class RulesClient { ); await this.validateActions(ruleType, data.actions); + // Validate intervals, if configured + if (ruleType.minimumScheduleInterval) { + const intervalInMs = parseDuration(data.schedule.interval); + const minimumScheduleIntervalInMs = parseDuration(ruleType.minimumScheduleInterval); + if (intervalInMs < minimumScheduleIntervalInMs) { + throw Boom.badRequest( + `Error updating rule: the interval is less than the minimum interval of ${ruleType.minimumScheduleInterval}` + ); + } + } + // Extract saved object references for this rule const { references, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts index 2bb92046db68f..fc8f272702e0d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts @@ -2268,4 +2268,30 @@ describe('create()', () => { expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); expect(taskManager.schedule).not.toHaveBeenCalled(); }); + + test('throws error when updating with an interval less than the minimum configured one', async () => { + ruleTypeRegistry.get.mockImplementation(() => ({ + id: '123', + name: 'Test', + actionGroups: [{ id: 'default', name: 'Default' }], + recoveryActionGroup: RecoveredActionGroup, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + async executor() {}, + producer: 'alerts', + minimumScheduleInterval: '5m', + useSavedObjectReferences: { + extractReferences: jest.fn(), + injectReferences: jest.fn(), + }, + })); + + const data = getMockData({ schedule: { interval: '1m' } }); + await expect(rulesClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error updating rule: the interval is less than the minimum interval of 5m"` + ); + expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); + expect(taskManager.schedule).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts index 1328b666f96e7..55ffc49fd3394 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts @@ -140,6 +140,7 @@ describe('update()', () => { recoveryActionGroup: RecoveredActionGroup, async executor() {}, producer: 'alerts', + minimumScheduleInterval: '5s', }); }); @@ -1966,4 +1967,49 @@ describe('update()', () => { ); }); }); + + test('throws error when updating with an interval less than the minimum configured one', async () => { + await expect( + rulesClient.update({ + id: '1', + data: { + schedule: { interval: '1s' }, + name: 'abc', + tags: ['foo'], + params: { + bar: true, + }, + throttle: null, + notifyWhen: 'onActiveAlert', + actions: [ + { + group: 'default', + id: '1', + params: { + foo: true, + }, + }, + { + group: 'default', + id: '1', + params: { + foo: true, + }, + }, + { + group: 'default', + id: '2', + params: { + foo: true, + }, + }, + ], + }, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error updating rule: the interval is less than the minimum interval of 5s"` + ); + expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); + expect(taskManager.schedule).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index c73ce86acf785..1dc8291d28756 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -157,6 +157,8 @@ export interface AlertType< injectReferences: (params: ExtractedParams, references: SavedObjectReference[]) => Params; }; isExportable: boolean; + defaultScheduleInterval?: string; + minimumScheduleInterval?: string; ruleTaskTimeout?: string; } export type UntypedAlertType = AlertType< diff --git a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts index bed7b09110d87..c69cbcfe8ac04 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts @@ -36,3 +36,5 @@ export enum SORT_ORDERS { } export const DEFAULT_SEARCH_PAGE_SIZE: number = 10; + +export const DEFAULT_ALERT_INTERVAL = '1m'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 2b13bdf613d96..3b15295cf7a3a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -171,6 +171,7 @@ export const AlertDetails: React.FunctionComponent = ({ }} actionTypeRegistry={actionTypeRegistry} ruleTypeRegistry={ruleTypeRegistry} + ruleType={alertType} onSave={setAlert} /> )} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx index 514594ffb855b..4ae570a62f7d9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx @@ -69,7 +69,8 @@ describe('alert_add', () => { async function setup( initialValues?: Partial, - onClose: AlertAddProps['onClose'] = jest.fn() + onClose: AlertAddProps['onClose'] = jest.fn(), + defaultScheduleInterval?: string ) { const mocks = coreMock.createSetup(); const { loadAlertTypes } = jest.requireMock('../../lib/alert_api'); @@ -84,6 +85,7 @@ describe('alert_add', () => { }, ], defaultActionGroupId: 'testActionGroup', + defaultScheduleInterval, minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, producer: ALERTS_FEATURE_ID, @@ -243,6 +245,26 @@ describe('alert_add', () => { expect(onClose).toHaveBeenCalledWith(AlertFlyoutCloseReason.SAVED); }); + + it('should enforce any default inteval', async () => { + await setup({ alertTypeId: 'my-alert-type' }, jest.fn(), '3h'); + await delay(1000); + + // Wait for handlers to fire + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + const intervalInputUnit = wrapper + .find('[data-test-subj="intervalInputUnit"]') + .first() + .getElement().props.value; + const intervalInput = wrapper.find('[data-test-subj="intervalInput"]').first().getElement() + .props.value; + expect(intervalInputUnit).toBe('h'); + expect(intervalInput).toBe(3); + }); }); function mockAlert(overloads: Partial = {}): Alert { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx index 5e4ca42523b39..2b376ea0d0b30 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx @@ -17,10 +17,12 @@ import { AlertFlyoutCloseReason, IErrorObject, AlertAddProps, + RuleTypeIndex, } from '../../../types'; -import { AlertForm, getAlertActionErrors, getAlertErrors, isValidAlert } from './alert_form'; +import { AlertForm } from './alert_form'; +import { getAlertActionErrors, getAlertErrors, isValidAlert } from './alert_errors'; import { alertReducer, InitialAlert, InitialAlertReducer } from './alert_reducer'; -import { createAlert } from '../../lib/alert_api'; +import { createAlert, loadAlertTypes } from '../../lib/alert_api'; import { HealthCheck } from '../../components/health_check'; import { ConfirmAlertSave } from './confirm_alert_save'; import { ConfirmAlertClose } from './confirm_alert_close'; @@ -30,6 +32,7 @@ import { HealthContextProvider } from '../../context/health_context'; import { useKibana } from '../../../common/lib/kibana'; import { hasAlertChanged, haveAlertParamsChanged } from './has_alert_changed'; import { getAlertWithInvalidatedFields } from '../../lib/value_validators'; +import { DEFAULT_ALERT_INTERVAL } from '../../constants'; const AlertAdd = ({ consumer, @@ -39,26 +42,28 @@ const AlertAdd = ({ canChangeTrigger, alertTypeId, initialValues, + reloadAlerts, onSave, metadata, + ...props }: AlertAddProps) => { const onSaveHandler = onSave ?? reloadAlerts; - const initialAlert: InitialAlert = useMemo( - () => ({ + + const initialAlert: InitialAlert = useMemo(() => { + return { params: {}, consumer, alertTypeId, schedule: { - interval: '1m', + interval: DEFAULT_ALERT_INTERVAL, }, actions: [], tags: [], notifyWhen: 'onActionGroupChange', ...(initialValues ? initialValues : {}), - }), - [alertTypeId, consumer, initialValues] - ); + }; + }, [alertTypeId, consumer, initialValues]); const [{ alert }, dispatch] = useReducer(alertReducer as InitialAlertReducer, { alert: initialAlert, @@ -67,6 +72,10 @@ const AlertAdd = ({ const [isSaving, setIsSaving] = useState(false); const [isConfirmAlertSaveModalOpen, setIsConfirmAlertSaveModalOpen] = useState(false); const [isConfirmAlertCloseModalOpen, setIsConfirmAlertCloseModalOpen] = useState(false); + const [ruleTypeIndex, setRuleTypeIndex] = useState( + props.ruleTypeIndex + ); + const [changedFromDefaultInterval, setChangedFromDefaultInterval] = useState(false); const setAlert = (value: InitialAlert) => { dispatch({ command: { type: 'setAlert' }, payload: { key: 'alert', value } }); @@ -90,6 +99,19 @@ const AlertAdd = ({ } }, [alertTypeId]); + useEffect(() => { + if (!props.ruleTypeIndex) { + (async () => { + const alertTypes = await loadAlertTypes({ http }); + const index: RuleTypeIndex = new Map(); + for (const alertType of alertTypes) { + index.set(alertType.id, alertType); + } + setRuleTypeIndex(index); + })(); + } + }, [props.ruleTypeIndex, http]); + useEffect(() => { if (isEmpty(alert.params) && !isEmpty(initialAlertParams)) { // alert params are explicitly cleared when the alert type is cleared. @@ -115,6 +137,21 @@ const AlertAdd = ({ })(); }, [alert, actionTypeRegistry]); + useEffect(() => { + if (alert.alertTypeId && ruleTypeIndex) { + const type = ruleTypeIndex.get(alert.alertTypeId); + if (type?.defaultScheduleInterval && !changedFromDefaultInterval) { + setAlertProperty('schedule', { interval: type.defaultScheduleInterval }); + } + } + }, [alert.alertTypeId, ruleTypeIndex, alert.schedule.interval, changedFromDefaultInterval]); + + useEffect(() => { + if (alert.schedule.interval !== DEFAULT_ALERT_INTERVAL && !changedFromDefaultInterval) { + setChangedFromDefaultInterval(true); + } + }, [alert.schedule.interval, changedFromDefaultInterval]); + const checkForChangesAndCloseFlyout = () => { if ( hasAlertChanged(alert, initialAlert, false) || @@ -138,9 +175,11 @@ const AlertAdd = ({ }; const alertType = alert.alertTypeId ? ruleTypeRegistry.get(alert.alertTypeId) : null; + const { alertBaseErrors, alertErrors, alertParamsErrors } = getAlertErrors( alert as Alert, - alertType + alertType, + alert.alertTypeId ? ruleTypeIndex?.get(alert.alertTypeId) : undefined ); // Confirm before saving if user is able to add actions but hasn't added any to this alert diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx index 1aea6c68acbf8..467f2af6ed704 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx @@ -35,6 +35,23 @@ jest.mock('../../lib/alert_api', () => ({ })), })); +jest.mock('./alert_errors', () => ({ + getAlertActionErrors: jest.fn().mockImplementation(() => { + return []; + }), + getAlertErrors: jest.fn().mockImplementation(() => ({ + alertParamsErrors: {}, + alertBaseErrors: {}, + alertErrors: { + name: new Array(), + interval: new Array(), + alertTypeId: new Array(), + actionConnectors: new Array(), + }, + })), + isValidAlert: jest.fn(), +})); + jest.mock('../../../common/lib/health_api', () => ({ triggersActionsUiHealth: jest.fn(() => ({ isAlertsAvailable: true })), })); @@ -47,7 +64,7 @@ describe('alert_edit', () => { mockedCoreSetup = coreMock.createSetup(); }); - async function setup() { + async function setup(initialAlertFields = {}) { const [ { application: { capabilities }, @@ -154,6 +171,7 @@ describe('alert_edit', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + ...initialAlertFields, }; actionTypeRegistry.get.mockReturnValueOnce(actionTypeModel); actionTypeRegistry.has.mockReturnValue(true); @@ -188,7 +206,11 @@ describe('alert_edit', () => { }); it('displays a toast message on save for server errors', async () => { - await setup(); + const { isValidAlert } = jest.requireMock('./alert_errors'); + (isValidAlert as jest.Mock).mockImplementation(() => { + return true; + }); + await setup({ name: undefined }); await act(async () => { wrapper.find('[data-test-subj="saveEditedAlertButton"]').first().simulate('click'); @@ -197,4 +219,12 @@ describe('alert_edit', () => { 'Fail message' ); }); + + it('should pass in the server alert type into `getAlertErrors`', async () => { + const { getAlertErrors } = jest.requireMock('./alert_errors'); + await setup(); + const lastCall = getAlertErrors.mock.calls[getAlertErrors.mock.calls.length - 1]; + expect(lastCall[2]).toBeDefined(); + expect(lastCall[2].id).toBe('my-alert-type'); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx index 8b79950d03ac9..f8c506fa1e8ba 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx @@ -24,10 +24,17 @@ import { } from '@elastic/eui'; import { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { Alert, AlertFlyoutCloseReason, AlertEditProps, IErrorObject } from '../../../types'; -import { AlertForm, getAlertActionErrors, getAlertErrors, isValidAlert } from './alert_form'; +import { + Alert, + AlertFlyoutCloseReason, + AlertEditProps, + IErrorObject, + AlertType, +} from '../../../types'; +import { AlertForm } from './alert_form'; +import { getAlertActionErrors, getAlertErrors, isValidAlert } from './alert_errors'; import { alertReducer, ConcreteAlertReducer } from './alert_reducer'; -import { updateAlert } from '../../lib/alert_api'; +import { updateAlert, loadAlertTypes } from '../../lib/alert_api'; import { HealthCheck } from '../../components/health_check'; import { HealthContextProvider } from '../../context/health_context'; import { useKibana } from '../../../common/lib/kibana'; @@ -43,6 +50,7 @@ export const AlertEdit = ({ ruleTypeRegistry, actionTypeRegistry, metadata, + ...props }: AlertEditProps) => { const onSaveHandler = onSave ?? reloadAlerts; const [{ alert }, dispatch] = useReducer(alertReducer as ConcreteAlertReducer, { @@ -55,6 +63,9 @@ export const AlertEdit = ({ const [isConfirmAlertCloseModalOpen, setIsConfirmAlertCloseModalOpen] = useState(false); const [alertActionsErrors, setAlertActionsErrors] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [serverRuleType, setServerRuleType] = useState | undefined>( + props.ruleType + ); const { http, @@ -75,9 +86,23 @@ export const AlertEdit = ({ })(); }, [alert, actionTypeRegistry]); + useEffect(() => { + if (!props.ruleType && !serverRuleType) { + (async () => { + const serverRuleTypes = await loadAlertTypes({ http }); + for (const _serverRuleType of serverRuleTypes) { + if (alertType.id === _serverRuleType.id) { + setServerRuleType(_serverRuleType); + } + } + })(); + } + }, [props.ruleType, alertType.id, serverRuleType, http]); + const { alertBaseErrors, alertErrors, alertParamsErrors } = getAlertErrors( alert as Alert, - alertType + alertType, + serverRuleType ); const checkForChangesAndCloseFlyout = () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.test.tsx new file mode 100644 index 0000000000000..5ca0fd9dafc18 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.test.tsx @@ -0,0 +1,284 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import uuid from 'uuid'; +import React, { Fragment } from 'react'; +import { + validateBaseProperties, + getAlertErrors, + getAlertActionErrors, + hasObjectErrors, + isValidAlert, +} from './alert_errors'; +import { Alert, AlertType, AlertTypeModel } from '../../../types'; +import { actionTypeRegistryMock } from '../../action_type_registry.mock'; + +describe('alert_errors', () => { + describe('validateBaseProperties()', () => { + it('should validate the name', () => { + const alert = mockAlert(); + alert.name = ''; + const result = validateBaseProperties(alert); + expect(result.errors).toStrictEqual({ + name: ['Name is required.'], + interval: [], + alertTypeId: [], + actionConnectors: [], + }); + }); + + it('should validate the interval', () => { + const alert = mockAlert(); + alert.schedule.interval = ''; + const result = validateBaseProperties(alert); + expect(result.errors).toStrictEqual({ + name: [], + interval: ['Check interval is required.'], + alertTypeId: [], + actionConnectors: [], + }); + }); + + it('should validate the minimumScheduleInterval', () => { + const alert = mockAlert(); + alert.schedule.interval = '2m'; + const result = validateBaseProperties( + alert, + mockserverRuleType({ minimumScheduleInterval: '5m' }) + ); + expect(result.errors).toStrictEqual({ + name: [], + interval: ['Interval is below minimum (5m) for this rule type'], + alertTypeId: [], + actionConnectors: [], + }); + }); + + it('should validate the alertTypeId', () => { + const alert = mockAlert(); + alert.alertTypeId = ''; + const result = validateBaseProperties(alert); + expect(result.errors).toStrictEqual({ + name: [], + interval: [], + alertTypeId: ['Rule type is required.'], + actionConnectors: [], + }); + }); + + it('should validate the connectors', () => { + const alert = mockAlert(); + alert.actions = [ + { + id: '1234', + actionTypeId: 'myActionType', + group: '', + params: { + name: 'yes', + }, + }, + ]; + const result = validateBaseProperties(alert); + expect(result.errors).toStrictEqual({ + name: [], + interval: [], + alertTypeId: [], + actionConnectors: ['Action for myActionType connector is required.'], + }); + }); + }); + + describe('getAlertErrors()', () => { + it('should return all errors', () => { + const result = getAlertErrors( + mockAlert({ + name: '', + }), + mockAlertTypeModel({ + validate: () => ({ + errors: { + field: ['This is wrong'], + }, + }), + }), + mockserverRuleType() + ); + expect(result).toStrictEqual({ + alertParamsErrors: { field: ['This is wrong'] }, + alertBaseErrors: { + name: ['Name is required.'], + interval: [], + alertTypeId: [], + actionConnectors: [], + }, + alertErrors: { + name: ['Name is required.'], + field: ['This is wrong'], + interval: [], + alertTypeId: [], + actionConnectors: [], + }, + }); + }); + }); + + describe('getAlertActionErrors()', () => { + it('should return an array of errors', async () => { + const actionTypeRegistry = actionTypeRegistryMock.create(); + actionTypeRegistry.get.mockImplementation((actionTypeId: string) => ({ + ...actionTypeRegistryMock.createMockActionTypeModel(), + validateParams: jest.fn().mockImplementation(() => ({ + errors: { + [actionTypeId]: ['Yes, this failed'], + }, + })), + })); + const result = await getAlertActionErrors( + mockAlert({ + actions: [ + { + id: '1234', + actionTypeId: 'myActionType', + group: '', + params: { + name: 'yes', + }, + }, + { + id: '5678', + actionTypeId: 'myActionType2', + group: '', + params: { + name: 'yes', + }, + }, + ], + }), + actionTypeRegistry + ); + expect(result).toStrictEqual([ + { + myActionType: ['Yes, this failed'], + }, + { + myActionType2: ['Yes, this failed'], + }, + ]); + }); + }); + + describe('hasObjectErrors()', () => { + it('should return true for any errors', () => { + expect( + hasObjectErrors({ + foo: ['1'], + }) + ).toBe(true); + expect( + hasObjectErrors({ + foo: { + foo: ['1'], + }, + }) + ).toBe(true); + }); + it('should return false for no errors', () => { + expect(hasObjectErrors({})).toBe(false); + }); + }); + + describe('isValidAlert()', () => { + it('should return true for a valid alert', () => { + const result = isValidAlert(mockAlert(), {}, []); + expect(result).toBe(true); + }); + it('should return false for an invalid alert', () => { + expect( + isValidAlert( + mockAlert(), + { + name: ['This is wrong'], + }, + [] + ) + ).toBe(false); + expect( + isValidAlert(mockAlert(), {}, [ + { + name: ['This is wrong'], + }, + ]) + ).toBe(false); + }); + }); +}); + +function mockserverRuleType( + overloads: Partial> = {} +): AlertType { + return { + actionGroups: [], + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { + id: 'recovery', + name: 'doRecovery', + }, + id: 'myAppAlertType', + name: 'myAppAlertType', + producer: 'myApp', + authorizedConsumers: {}, + enabledInLicense: true, + actionVariables: { + context: [], + state: [], + params: [], + }, + ...overloads, + }; +} + +function mockAlertTypeModel(overloads: Partial = {}): AlertTypeModel { + return { + id: 'alertTypeModel', + description: 'some alert', + iconClass: 'something', + documentationUrl: null, + validate: () => ({ errors: {} }), + alertParamsExpression: () => , + requiresAppContext: false, + ...overloads, + }; +} + +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, + notifyWhen: null, + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, + ...overloads, + }; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.ts new file mode 100644 index 0000000000000..3ca6a822b2d2d --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_errors.ts @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { isObject } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { parseDuration } from '../../../../../alerting/common/parse_duration'; +import { + AlertTypeModel, + Alert, + IErrorObject, + AlertAction, + AlertType, + ValidationResult, + ActionTypeRegistryContract, +} from '../../../types'; +import { InitialAlert } from './alert_reducer'; + +export function validateBaseProperties( + alertObject: InitialAlert, + serverRuleType?: AlertType +): ValidationResult { + const validationResult = { errors: {} }; + const errors = { + name: new Array(), + interval: new Array(), + alertTypeId: new Array(), + actionConnectors: new Array(), + }; + validationResult.errors = errors; + if (!alertObject.name) { + errors.name.push( + i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredNameText', { + defaultMessage: 'Name is required.', + }) + ); + } + if (alertObject.schedule.interval.length < 2) { + errors.interval.push( + i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredIntervalText', { + defaultMessage: 'Check interval is required.', + }) + ); + } else if (serverRuleType?.minimumScheduleInterval) { + const duration = parseDuration(alertObject.schedule.interval); + const minimumDuration = parseDuration(serverRuleType.minimumScheduleInterval); + if (duration < minimumDuration) { + errors.interval.push( + i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.belowMinimumText', { + defaultMessage: 'Interval is below minimum ({minimum}) for this rule type', + values: { + minimum: serverRuleType.minimumScheduleInterval, + }, + }) + ); + } + } + + if (!alertObject.alertTypeId) { + errors.alertTypeId.push( + i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredRuleTypeIdText', { + defaultMessage: 'Rule type is required.', + }) + ); + } + const emptyConnectorActions = alertObject.actions.find( + (actionItem) => /^\d+$/.test(actionItem.id) && Object.keys(actionItem.params).length > 0 + ); + if (emptyConnectorActions !== undefined) { + errors.actionConnectors.push( + i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredActionConnector', { + defaultMessage: 'Action for {actionTypeId} connector is required.', + values: { actionTypeId: emptyConnectorActions.actionTypeId }, + }) + ); + } + return validationResult; +} + +export function getAlertErrors( + alert: Alert, + alertTypeModel: AlertTypeModel | null, + serverRuleType?: AlertType +) { + const alertParamsErrors: IErrorObject = alertTypeModel + ? alertTypeModel.validate(alert.params).errors + : []; + const alertBaseErrors = validateBaseProperties(alert, serverRuleType).errors as IErrorObject; + const alertErrors = { + ...alertParamsErrors, + ...alertBaseErrors, + } as IErrorObject; + + return { + alertParamsErrors, + alertBaseErrors, + alertErrors, + }; +} + +export async function getAlertActionErrors( + alert: Alert, + actionTypeRegistry: ActionTypeRegistryContract +): Promise { + return await Promise.all( + alert.actions.map( + async (alertAction: AlertAction) => + ( + await actionTypeRegistry.get(alertAction.actionTypeId)?.validateParams(alertAction.params) + ).errors + ) + ); +} + +export const hasObjectErrors: (errors: IErrorObject) => boolean = (errors) => + !!Object.values(errors).find((errorList) => { + if (isObject(errorList)) return hasObjectErrors(errorList as IErrorObject); + return errorList.length >= 1; + }); + +export function isValidAlert( + alertObject: InitialAlert | Alert, + validationResult: IErrorObject, + actionsErrors: IErrorObject[] +): alertObject is Alert { + return ( + !hasObjectErrors(validationResult) && + actionsErrors.every((error: IErrorObject) => !hasObjectErrors(error)) + ); +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_form.tsx index 5facda85e6c89..3f6bf3c955e8b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_form.tsx @@ -35,7 +35,7 @@ import { EuiToolTip, EuiCallOut, } from '@elastic/eui'; -import { capitalize, isObject } from 'lodash'; +import { capitalize } from 'lodash'; import { KibanaFeature } from '../../../../../features/public'; import { getDurationNumberInItsUnit, @@ -48,9 +48,8 @@ import { Alert, IErrorObject, AlertAction, - AlertTypeIndex, + RuleTypeIndex, AlertType, - ValidationResult, RuleTypeRegistryContract, ActionTypeRegistryContract, } from '../../../types'; @@ -74,101 +73,10 @@ import { checkAlertTypeEnabled } from '../../lib/check_alert_type_enabled'; import { alertTypeCompare, alertTypeGroupCompare } from '../../lib/alert_type_compare'; import { VIEW_LICENSE_OPTIONS_LINK } from '../../../common/constants'; import { SectionLoading } from '../../components/section_loading'; +import { DEFAULT_ALERT_INTERVAL } from '../../constants'; const ENTER_KEY = 13; -export function validateBaseProperties(alertObject: InitialAlert): ValidationResult { - const validationResult = { errors: {} }; - const errors = { - name: new Array(), - interval: new Array(), - alertTypeId: new Array(), - actionConnectors: new Array(), - }; - validationResult.errors = errors; - if (!alertObject.name) { - errors.name.push( - i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredNameText', { - defaultMessage: 'Name is required.', - }) - ); - } - if (alertObject.schedule.interval.length < 2) { - errors.interval.push( - i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredIntervalText', { - defaultMessage: 'Check interval is required.', - }) - ); - } - if (!alertObject.alertTypeId) { - errors.alertTypeId.push( - i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredRuleTypeIdText', { - defaultMessage: 'Rule type is required.', - }) - ); - } - const emptyConnectorActions = alertObject.actions.find( - (actionItem) => /^\d+$/.test(actionItem.id) && Object.keys(actionItem.params).length > 0 - ); - if (emptyConnectorActions !== undefined) { - errors.actionConnectors.push( - i18n.translate('xpack.triggersActionsUI.sections.alertForm.error.requiredActionConnector', { - defaultMessage: 'Action for {actionTypeId} connector is required.', - values: { actionTypeId: emptyConnectorActions.actionTypeId }, - }) - ); - } - return validationResult; -} - -export function getAlertErrors(alert: Alert, alertTypeModel: AlertTypeModel | null) { - const alertParamsErrors: IErrorObject = alertTypeModel - ? alertTypeModel.validate(alert.params).errors - : []; - const alertBaseErrors = validateBaseProperties(alert).errors as IErrorObject; - const alertErrors = { - ...alertParamsErrors, - ...alertBaseErrors, - } as IErrorObject; - - return { - alertParamsErrors, - alertBaseErrors, - alertErrors, - }; -} - -export async function getAlertActionErrors( - alert: Alert, - actionTypeRegistry: ActionTypeRegistryContract -): Promise { - return await Promise.all( - alert.actions.map( - async (alertAction: AlertAction) => - ( - await actionTypeRegistry.get(alertAction.actionTypeId)?.validateParams(alertAction.params) - ).errors - ) - ); -} - -export const hasObjectErrors: (errors: IErrorObject) => boolean = (errors) => - !!Object.values(errors).find((errorList) => { - if (isObject(errorList)) return hasObjectErrors(errorList as IErrorObject); - return errorList.length >= 1; - }); - -export function isValidAlert( - alertObject: InitialAlert | Alert, - validationResult: IErrorObject, - actionsErrors: IErrorObject[] -): alertObject is Alert { - return ( - !hasObjectErrors(validationResult) && - actionsErrors.every((error: IErrorObject) => !hasObjectErrors(error)) - ); -} - function getProducerFeatureName(producer: string, kibanaFeatures: KibanaFeature[]) { return kibanaFeatures.find((featureItem) => featureItem.id === producer)?.name; } @@ -186,6 +94,9 @@ interface AlertFormProps> { metadata?: MetaData; } +const defaultScheduleInterval = getDurationNumberInItsUnit(DEFAULT_ALERT_INTERVAL); +const defaultScheduleIntervalUnit = getDurationUnitValue(DEFAULT_ALERT_INTERVAL); + export const AlertForm = ({ alert, canChangeTrigger = true, @@ -212,10 +123,14 @@ export const AlertForm = ({ const [alertTypeModel, setAlertTypeModel] = useState(null); const [alertInterval, setAlertInterval] = useState( - alert.schedule.interval ? getDurationNumberInItsUnit(alert.schedule.interval) : undefined + alert.schedule.interval + ? getDurationNumberInItsUnit(alert.schedule.interval) + : defaultScheduleInterval ); const [alertIntervalUnit, setAlertIntervalUnit] = useState( - alert.schedule.interval ? getDurationUnitValue(alert.schedule.interval) : 'm' + alert.schedule.interval + ? getDurationUnitValue(alert.schedule.interval) + : defaultScheduleIntervalUnit ); const [alertThrottle, setAlertThrottle] = useState( alert.throttle ? getDurationNumberInItsUnit(alert.throttle) : null @@ -224,7 +139,7 @@ export const AlertForm = ({ alert.throttle ? getDurationUnitValue(alert.throttle) : 'h' ); const [defaultActionGroupId, setDefaultActionGroupId] = useState(undefined); - const [alertTypesIndex, setAlertTypesIndex] = useState(null); + const [ruleTypeIndex, setRuleTypeIndex] = useState(null); const [availableAlertTypes, setAvailableAlertTypes] = useState< Array<{ alertTypeModel: AlertTypeModel; alertType: AlertType }> @@ -243,14 +158,14 @@ export const AlertForm = ({ (async () => { try { const alertTypesResult = await loadAlertTypes({ http }); - const index: AlertTypeIndex = new Map(); + const index: RuleTypeIndex = new Map(); for (const alertTypeItem of alertTypesResult) { index.set(alertTypeItem.id, alertTypeItem); } if (alert.alertTypeId && index.has(alert.alertTypeId)) { setDefaultActionGroupId(index.get(alert.alertTypeId)!.defaultActionGroupId); } - setAlertTypesIndex(index); + setRuleTypeIndex(index); const availableAlertTypesResult = getAvailableAlertTypes(alertTypesResult); setAvailableAlertTypes(availableAlertTypesResult); @@ -287,10 +202,24 @@ export const AlertForm = ({ useEffect(() => { setAlertTypeModel(alert.alertTypeId ? ruleTypeRegistry.get(alert.alertTypeId) : null); - if (alert.alertTypeId && alertTypesIndex && alertTypesIndex.has(alert.alertTypeId)) { - setDefaultActionGroupId(alertTypesIndex.get(alert.alertTypeId)!.defaultActionGroupId); + if (alert.alertTypeId && ruleTypeIndex && ruleTypeIndex.has(alert.alertTypeId)) { + setDefaultActionGroupId(ruleTypeIndex.get(alert.alertTypeId)!.defaultActionGroupId); + } + }, [alert, alert.alertTypeId, ruleTypeIndex, ruleTypeRegistry]); + + useEffect(() => { + if (alert.schedule.interval) { + const interval = getDurationNumberInItsUnit(alert.schedule.interval); + const intervalUnit = getDurationUnitValue(alert.schedule.interval); + + if (interval !== defaultScheduleInterval) { + setAlertInterval(interval); + } + if (intervalUnit !== defaultScheduleIntervalUnit) { + setAlertIntervalUnit(intervalUnit); + } } - }, [alert, alert.alertTypeId, alertTypesIndex, ruleTypeRegistry]); + }, [alert.schedule.interval]); const setAlertProperty = useCallback( (key: Key, value: Alert[Key] | null) => { @@ -372,9 +301,7 @@ export const AlertForm = ({ ? !item.alertTypeModel.requiresAppContext : item.alertType!.producer === alert.consumer ); - const selectedAlertType = alert?.alertTypeId - ? alertTypesIndex?.get(alert?.alertTypeId) - : undefined; + const selectedAlertType = alert?.alertTypeId ? ruleTypeIndex?.get(alert?.alertTypeId) : undefined; const recoveryActionGroup = selectedAlertType?.recoveryActionGroup?.id; const getDefaultActionParams = useCallback( (actionTypeId: string, actionGroupId: string): Record | undefined => @@ -499,8 +426,8 @@ export const AlertForm = ({ setActions([]); setAlertTypeModel(item.alertTypeItem); setAlertProperty('params', {}); - if (alertTypesIndex && alertTypesIndex.has(item.id)) { - setDefaultActionGroupId(alertTypesIndex.get(item.id)!.defaultActionGroupId); + if (ruleTypeIndex && ruleTypeIndex.has(item.id)) { + setDefaultActionGroupId(ruleTypeIndex.get(item.id)!.defaultActionGroupId); } }} /> @@ -518,8 +445,8 @@ export const AlertForm = ({
- {alert.alertTypeId && alertTypesIndex && alertTypesIndex.has(alert.alertTypeId) - ? alertTypesIndex.get(alert.alertTypeId)!.name + {alert.alertTypeId && ruleTypeIndex && ruleTypeIndex.has(alert.alertTypeId) + ? ruleTypeIndex.get(alert.alertTypeId)!.name : ''}
@@ -870,7 +797,7 @@ export const AlertForm = ({ ) : null} {alertTypeNodes} - ) : alertTypesIndex ? ( + ) : ruleTypeIndex ? ( ) : ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 941d400104082..1daaf3b996126 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -33,7 +33,14 @@ import { import { useHistory } from 'react-router-dom'; import { isEmpty } from 'lodash'; -import { ActionType, Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; +import { + ActionType, + Alert, + AlertTableItem, + AlertType, + RuleTypeIndex, + Pagination, +} from '../../../../types'; import { AlertAdd, AlertEdit } from '../../alert_form'; import { BulkOperationPopover } from '../../common/components/bulk_operation_popover'; import { AlertQuickEditButtonsWithApi as AlertQuickEditButtons } from '../../common/components/alert_quick_edit_buttons'; @@ -74,7 +81,7 @@ const ENTER_KEY = 13; interface AlertTypeState { isLoading: boolean; isInitialized: boolean; - data: AlertTypeIndex; + data: RuleTypeIndex; } interface AlertState { isLoading: boolean; @@ -161,7 +168,7 @@ export const AlertsList: React.FunctionComponent = () => { try { setAlertTypesState({ ...alertTypesState, isLoading: true }); const alertTypes = await loadAlertTypes({ http }); - const index: AlertTypeIndex = new Map(); + const index: RuleTypeIndex = new Map(); for (const alertType of alertTypes) { index.set(alertType.id, alertType); } @@ -895,6 +902,7 @@ export const AlertsList: React.FunctionComponent = () => { }} actionTypeRegistry={actionTypeRegistry} ruleTypeRegistry={ruleTypeRegistry} + ruleTypeIndex={alertTypesState.data} onSave={loadAlertsData} /> )} @@ -906,6 +914,9 @@ export const AlertsList: React.FunctionComponent = () => { }} actionTypeRegistry={actionTypeRegistry} ruleTypeRegistry={ruleTypeRegistry} + ruleType={ + alertTypesState.data.get(currentRuleToEdit.alertTypeId) as AlertType + } onSave={loadAlertsData} /> )} @@ -944,17 +955,17 @@ function filterAlertsById(alerts: Alert[], ids: string[]): Alert[] { function convertAlertsToTableItems( alerts: Alert[], - alertTypesIndex: AlertTypeIndex, + ruleTypeIndex: RuleTypeIndex, canExecuteActions: boolean ) { return alerts.map((alert) => ({ ...alert, actionsCount: alert.actions.length, tagsText: alert.tags.join(', '), - alertType: alertTypesIndex.get(alert.alertTypeId)?.name ?? alert.alertTypeId, + alertType: ruleTypeIndex.get(alert.alertTypeId)?.name ?? alert.alertTypeId, isEditable: - hasAllPrivilege(alert, alertTypesIndex.get(alert.alertTypeId)) && + hasAllPrivilege(alert, ruleTypeIndex.get(alert.alertTypeId)) && (canExecuteActions || (!canExecuteActions && !alert.actions.length)), - enabledInLicense: !!alertTypesIndex.get(alert.alertTypeId)?.enabledInLicense, + enabledInLicense: !!ruleTypeIndex.get(alert.alertTypeId)?.enabledInLicense, })); } diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index ae4fd5152794f..2ef20f36b7ca9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -66,7 +66,7 @@ export { }; export type ActionTypeIndex = Record; -export type AlertTypeIndex = Map; +export type RuleTypeIndex = Map; export type ActionTypeRegistryContract< ActionConnector = unknown, ActionParams = unknown @@ -197,6 +197,8 @@ export interface AlertType< | 'minimumLicenseRequired' | 'recoveryActionGroup' | 'defaultActionGroupId' + | 'defaultScheduleInterval' + | 'minimumScheduleInterval' > { actionVariables: ActionVariables; authorizedConsumers: Record; @@ -285,6 +287,7 @@ export interface AlertEditProps> { reloadAlerts?: () => Promise; onSave?: () => Promise; metadata?: MetaData; + ruleType?: AlertType; } export interface AlertAddProps> { @@ -299,4 +302,5 @@ export interface AlertAddProps> { reloadAlerts?: () => Promise; onSave?: () => Promise; metadata?: MetaData; + ruleTypeIndex?: RuleTypeIndex; } From a3895208498e835a692fee918191b4b20802bb59 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 11 Oct 2021 20:27:46 +0200 Subject: [PATCH 17/73] [Utpime] Remove unnecessary usememo in url params hooks (#114252) --- x-pack/plugins/uptime/public/hooks/use_url_params.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/uptime/public/hooks/use_url_params.ts b/x-pack/plugins/uptime/public/hooks/use_url_params.ts index 329e0ccef4d96..1318b635693c7 100644 --- a/x-pack/plugins/uptime/public/hooks/use_url_params.ts +++ b/x-pack/plugins/uptime/public/hooks/use_url_params.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect } from 'react'; import { parse, stringify } from 'query-string'; import { useLocation, useHistory } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; @@ -28,7 +28,7 @@ const getParsedParams = (search: string) => { export const useGetUrlParams: GetUrlParams = () => { const { search } = useLocation(); - return useMemo(() => getSupportedUrlParams(getParsedParams(search)), [search]); + return getSupportedUrlParams(getParsedParams(search)); }; const getMapFromFilters = (value: any): Map | undefined => { From e8d16cddca6003383c972a01229f9a284799a2ed Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Mon, 11 Oct 2021 13:30:33 -0500 Subject: [PATCH 18/73] skip flaky suite. #114541, #114542 --- x-pack/test/accessibility/apps/index_lifecycle_management.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/test/accessibility/apps/index_lifecycle_management.ts b/x-pack/test/accessibility/apps/index_lifecycle_management.ts index da56cfd702abf..65faa77fc497b 100644 --- a/x-pack/test/accessibility/apps/index_lifecycle_management.ts +++ b/x-pack/test/accessibility/apps/index_lifecycle_management.ts @@ -57,7 +57,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { throw new Error(`Could not find ${policyName} in policy table`); }; - describe('Index Lifecycle Management', async () => { + // FLAKY + // https://github.com/elastic/kibana/issues/114541 + // https://github.com/elastic/kibana/issues/114542 + describe.skip('Index Lifecycle Management', async () => { before(async () => { await esClient.ilm.putLifecycle({ policy: POLICY_NAME, body: POLICY_ALL_PHASES }); await esClient.indices.putIndexTemplate({ From 328da6f720f6988cd307bccdd4e4be5a0f783ba8 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Mon, 11 Oct 2021 16:18:10 -0400 Subject: [PATCH 19/73] add default sort props (#114294) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/monitoring/public/application/hooks/use_table.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_table.ts b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts index 45d1f717f5d49..be1983c373c27 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_table.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts @@ -9,6 +9,7 @@ import { useState, useCallback } from 'react'; import { EuiTableSortingType } from '@elastic/eui'; import { euiTableStorageGetter, euiTableStorageSetter } from '../../components/table'; import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; +import { EUI_SORT_ASCENDING } from '../../../common/constants'; interface Pagination { pageSize: number; @@ -77,7 +78,9 @@ export function useTable(storageKey: string) { ); // get initial state from localStorage - const [sorting, setSorting] = useState(storageData.sort || { sort: {} }); + const [sorting, setSorting] = useState( + storageData.sort || { sort: { field: 'name', direction: EUI_SORT_ASCENDING } } + ); const [query, setQuery] = useState(''); From de42e5329f8b76bcc7bb07e0fceb4739a74fe7ea Mon Sep 17 00:00:00 2001 From: Sandra G Date: Mon, 11 Oct 2021 16:18:29 -0400 Subject: [PATCH 20/73] [Stack Monitoring] add test subject to tab (#114319) * pass test subject to advanced link and change name in angular version to be generic * change name in functional test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/pages/elasticsearch/item_template.tsx | 1 + x-pack/plugins/monitoring/public/directives/main/index.html | 2 +- .../functional/services/monitoring/elasticsearch_node_detail.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx index 1f06ba18bf102..05d567a9b3ff7 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx @@ -25,6 +25,7 @@ export const ItemTemplate: React.FC = (props) => { }, { id: 'advanced', + testSubj: 'esItemDetailAdvancedLink', label: i18n.translate('xpack.monitoring.esItemNavigation.advancedLinkText', { defaultMessage: 'Advanced', }), diff --git a/x-pack/plugins/monitoring/public/directives/main/index.html b/x-pack/plugins/monitoring/public/directives/main/index.html index fb24d9e678d56..558ed5e874cd6 100644 --- a/x-pack/plugins/monitoring/public/directives/main/index.html +++ b/x-pack/plugins/monitoring/public/directives/main/index.html @@ -103,7 +103,7 @@

{{pageTitle || monitoringMain.instance}} Date: Mon, 11 Oct 2021 20:30:54 +0000 Subject: [PATCH 21/73] auto-upgrade polyfills --- renovate.json5 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/renovate.json5 b/renovate.json5 index dea7d311bae16..b08d7e0bcec1e 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -75,6 +75,16 @@ labels: ['Team:Operations', 'release_note:skip'], enabled: true, }, + { + groupName: 'polyfills', + packageNames: ['core-js'], + matchPackagePatterns: ["polyfill"], + excludePackageNames: ['@loaders.gl/polyfills'], + reviewers: ['team:kibana-operations'], + matchBaseBranches: ['master'], + labels: ['Team:Operations', 'release_note:skip'], + enabled: true, + }, { groupName: 'vega related modules', packageNames: ['vega', 'vega-lite', 'vega-schema-url-parser', 'vega-tooltip'], From a03aa7b7faa0bef0ef4d3c0043c7cdf7f8e3890f Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 11 Oct 2021 13:44:50 +0100 Subject: [PATCH 22/73] skip flaky suites (#114418) --- .../functional/apps/maps/documents_source/docvalue_fields.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js index 3479f292374d2..64c6c2b6749e6 100644 --- a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js +++ b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js @@ -11,7 +11,8 @@ export default function ({ getPageObjects, getService }) { const PageObjects = getPageObjects(['maps']); const security = getService('security'); - describe('docvalue_fields', () => { + // FLAKY: https://github.com/elastic/kibana/issues/114418 + describe.skip('docvalue_fields', () => { before(async () => { await security.testUser.setRoles(['global_maps_read', 'test_logstash_reader'], false); await PageObjects.maps.loadSavedMap('document example'); From f88901c6ac37440beff1629685055e0bca64221b Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Mon, 11 Oct 2021 23:50:35 +0200 Subject: [PATCH 23/73] Log Unhandled rejection stack (#113614) * Refactor state types * Log the stack trace of unhandled promise rejections * Revert "Refactor state types" This reverts commit 6a5123a1b2d2b40089c94109619c471b3c33acf2. * Fix types * code review feedback --- .../environment/environment_service.test.ts | 26 +++++++++++++++++++ .../server/environment/environment_service.ts | 5 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/core/server/environment/environment_service.test.ts b/src/core/server/environment/environment_service.test.ts index 34647d090b995..4b074482248b4 100644 --- a/src/core/server/environment/environment_service.test.ts +++ b/src/core/server/environment/environment_service.test.ts @@ -135,6 +135,32 @@ describe('UuidService', () => { expect(logger.get('process').warn).not.toHaveBeenCalled(); }); }); + + describe('unhandledRejection warnings', () => { + it('logs warn for an unhandeld promise rejected with an Error', async () => { + await service.preboot(); + + const err = new Error('something went wrong'); + process.emit('unhandledRejection', err, new Promise((res, rej) => rej(err))); + + expect(logger.get('process').warn).toHaveBeenCalledTimes(1); + expect(loggingSystemMock.collect(logger).warn[0][0]).toMatch( + /Detected an unhandled Promise rejection: Error: something went wrong\n.*at / + ); + }); + + it('logs warn for an unhandeld promise rejected with a string', async () => { + await service.preboot(); + + const err = 'something went wrong'; + process.emit('unhandledRejection', err, new Promise((res, rej) => rej(err))); + + expect(logger.get('process').warn).toHaveBeenCalledTimes(1); + expect(loggingSystemMock.collect(logger).warn[0][0]).toMatch( + /Detected an unhandled Promise rejection: "something went wrong"/ + ); + }); + }); }); describe('#setup()', () => { diff --git a/src/core/server/environment/environment_service.ts b/src/core/server/environment/environment_service.ts index f96b616256577..472883c1f482c 100644 --- a/src/core/server/environment/environment_service.ts +++ b/src/core/server/environment/environment_service.ts @@ -54,9 +54,10 @@ export class EnvironmentService { this.configService.atPath(pidConfigDef.path).pipe(take(1)).toPromise(), ]); - // was present in the legacy `pid` file. + // Log unhandled rejections so that we can fix them in preparation for https://github.com/elastic/kibana/issues/77469 process.on('unhandledRejection', (reason) => { - this.log.warn(`Detected an unhandled Promise rejection.\n${reason}`); + const message = (reason as Error)?.stack ?? JSON.stringify(reason); + this.log.warn(`Detected an unhandled Promise rejection: ${message}`); }); process.on('warning', (warning) => { From c6b5136c3a5a95c9027e64c01a03ee52f30d264d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 11 Oct 2021 16:26:52 -0600 Subject: [PATCH 24/73] =?UTF-8?q?[Maps]=20fix=20docvalue=5Ffields=C2=B7js?= =?UTF-8?q?=20functional=20test=20(#114527)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Maps] fix docvalue_fields·js functional test * remove unused * eslint * remove _type from check list, copied from 7.x branch and is not in 8.0 Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/maps/documents_source/docvalue_fields.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js index 64c6c2b6749e6..d1da193ac50a5 100644 --- a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js +++ b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js @@ -15,7 +15,6 @@ export default function ({ getPageObjects, getService }) { describe.skip('docvalue_fields', () => { before(async () => { await security.testUser.setRoles(['global_maps_read', 'test_logstash_reader'], false); - await PageObjects.maps.loadSavedMap('document example'); }); after(async () => { @@ -46,11 +45,14 @@ export default function ({ getPageObjects, getService }) { it('should format date fields as epoch_millis when data driven styling is applied to a date field', async () => { await PageObjects.maps.loadSavedMap('document example with data driven styles on date field'); const { rawResponse: response } = await PageObjects.maps.getResponse(); - const firstHit = response.hits.hits[0]; - expect(firstHit).to.only.have.keys(['_id', '_index', '_score', 'fields']); - expect(firstHit.fields).to.only.have.keys(['@timestamp', 'bytes', 'geo.coordinates']); - expect(firstHit.fields['@timestamp']).to.be.an('array'); - expect(firstHit.fields['@timestamp'][0]).to.eql('1442709321445'); + const targetHit = response.hits.hits.find((hit) => { + return hit._id === 'AU_x3_g4GFA8no6QjkSR'; + }); + expect(targetHit).not.to.be(undefined); + expect(targetHit).to.only.have.keys(['_id', '_index', '_score', 'fields']); + expect(targetHit.fields).to.only.have.keys(['@timestamp', 'bytes', 'geo.coordinates']); + expect(targetHit.fields['@timestamp']).to.be.an('array'); + expect(targetHit.fields['@timestamp'][0]).to.eql('1442709321445'); }); }); } From a0b55b316e23a80de5d755864c7acd656b44441f Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:29:50 -0400 Subject: [PATCH 25/73] [Core][Deprecations] omit deprecationDetails if needed it in the reques (#114399) * omit deprecationDetails if needed it * review I * doc update Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...r.deprecationsdetails.correctiveactions.md | 1 + ...-plugin-core-server.deprecationsdetails.md | 2 +- .../deprecations/deprecations_client.test.ts | 33 +++++++++++++++++++ .../deprecations/deprecations_client.ts | 4 +-- src/core/server/deprecations/README.mdx | 2 +- src/core/server/deprecations/types.ts | 2 ++ src/core/server/server.api.md | 1 + 7 files changed, 41 insertions(+), 4 deletions(-) diff --git a/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.correctiveactions.md b/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.correctiveactions.md index 657c62a21c581..d7d10651033bf 100644 --- a/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.correctiveactions.md +++ b/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.correctiveactions.md @@ -16,6 +16,7 @@ correctiveActions: { body?: { [key: string]: any; }; + omitContextFromBody?: boolean; }; manualSteps: string[]; }; diff --git a/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.md b/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.md index 86418a1d0c1c3..2ff9f4b792f5d 100644 --- a/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.md +++ b/docs/development/core/server/kibana-plugin-core-server.deprecationsdetails.md @@ -15,7 +15,7 @@ export interface DeprecationsDetails | Property | Type | Description | | --- | --- | --- | -| [correctiveActions](./kibana-plugin-core-server.deprecationsdetails.correctiveactions.md) | {
api?: {
path: string;
method: 'POST' | 'PUT';
body?: {
[key: string]: any;
};
};
manualSteps: string[];
} | corrective action needed to fix this deprecation. | +| [correctiveActions](./kibana-plugin-core-server.deprecationsdetails.correctiveactions.md) | {
api?: {
path: string;
method: 'POST' | 'PUT';
body?: {
[key: string]: any;
};
omitContextFromBody?: boolean;
};
manualSteps: string[];
} | corrective action needed to fix this deprecation. | | [deprecationType](./kibana-plugin-core-server.deprecationsdetails.deprecationtype.md) | 'config' | 'feature' | (optional) Used to identify between different deprecation types. Example use case: in Upgrade Assistant, we may want to allow the user to sort by deprecation type or show each type in a separate tab.Feel free to add new types if necessary. Predefined types are necessary to reduce having similar definitions with different keywords across kibana deprecations. | | [documentationUrl](./kibana-plugin-core-server.deprecationsdetails.documentationurl.md) | string | (optional) link to the documentation for more details on the deprecation. | | [level](./kibana-plugin-core-server.deprecationsdetails.level.md) | 'warning' | 'critical' | 'fetch_error' | levels: - warning: will not break deployment upon upgrade - critical: needs to be addressed before upgrade. - fetch\_error: Deprecations service failed to grab the deprecation details for the domain. | diff --git a/src/core/public/deprecations/deprecations_client.test.ts b/src/core/public/deprecations/deprecations_client.test.ts index cca81f4687a97..3c45b76cfecd2 100644 --- a/src/core/public/deprecations/deprecations_client.test.ts +++ b/src/core/public/deprecations/deprecations_client.test.ts @@ -197,5 +197,38 @@ describe('DeprecationsClient', () => { expect(result).toEqual({ status: 'fail', reason: mockResponse }); }); + + it('omit deprecationDetails in the request of the body', async () => { + const deprecationsClient = new DeprecationsClient({ http }); + const mockDeprecationDetails: DomainDeprecationDetails = { + title: 'some-title', + domainId: 'testPluginId-1', + message: 'some-message', + level: 'warning', + correctiveActions: { + api: { + path: 'some-path', + method: 'POST', + body: { + extra_param: 123, + }, + omitContextFromBody: true, + }, + manualSteps: ['manual-step'], + }, + }; + const result = await deprecationsClient.resolveDeprecation(mockDeprecationDetails); + + expect(http.fetch).toBeCalledTimes(1); + expect(http.fetch).toBeCalledWith({ + path: 'some-path', + method: 'POST', + asSystemRequest: true, + body: JSON.stringify({ + extra_param: 123, + }), + }); + expect(result).toEqual({ status: 'ok' }); + }); }); }); diff --git a/src/core/public/deprecations/deprecations_client.ts b/src/core/public/deprecations/deprecations_client.ts index 4b9cfca1986ba..01906c930d730 100644 --- a/src/core/public/deprecations/deprecations_client.ts +++ b/src/core/public/deprecations/deprecations_client.ts @@ -59,7 +59,7 @@ export class DeprecationsClient { }; } - const { body, method, path } = correctiveActions.api; + const { body, method, path, omitContextFromBody = false } = correctiveActions.api; try { await this.http.fetch({ path, @@ -67,7 +67,7 @@ export class DeprecationsClient { asSystemRequest: true, body: JSON.stringify({ ...body, - deprecationDetails: { domainId }, + ...(omitContextFromBody ? {} : { deprecationDetails: { domainId } }), }), }); return { status: 'ok' }; diff --git a/src/core/server/deprecations/README.mdx b/src/core/server/deprecations/README.mdx index 82a01995502e2..ed542610e753f 100644 --- a/src/core/server/deprecations/README.mdx +++ b/src/core/server/deprecations/README.mdx @@ -212,7 +212,7 @@ async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecations The deprecations API allows plugins to provide an API call that can be used to automatically fix specific deprecations. To do so create a `PUT` or `POST` route in your plugin and specify data you want to be passed in the payload for the deprecation. -In the example above, `/internal/security/users/test_dashboard_user` will be called when users click on `Quick Resolve` in the UA. The service will automatically pass the body provided in the api corrective action to provide context to the route for fixing the deprecation. +In the example above, `/internal/security/users/test_dashboard_user` will be called when users click on `Quick Resolve` in the UA. The service will automatically pass the body provided in the api corrective action to provide context to the route for fixing the deprecation. If you need to omit the deprecation details context in the request of the body, you can use the property `omitContextFromBody`. The deprecations service expects a `200` status code to recognize the corrective action as a success. diff --git a/src/core/server/deprecations/types.ts b/src/core/server/deprecations/types.ts index 7e276514a64d3..e24c6a13fceea 100644 --- a/src/core/server/deprecations/types.ts +++ b/src/core/server/deprecations/types.ts @@ -69,6 +69,8 @@ export interface DeprecationsDetails { body?: { [key: string]: any; }; + /* Allow to omit context in the request of the body */ + omitContextFromBody?: boolean; }; /** * Specify a list of manual steps users need to follow to diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index c92f767ce891d..a1fd69f5e1c7e 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -812,6 +812,7 @@ export interface DeprecationsDetails { body?: { [key: string]: any; }; + omitContextFromBody?: boolean; }; manualSteps: string[]; }; From 912eb0d9373ef17c27c2a1308ff8151dd8382e5a Mon Sep 17 00:00:00 2001 From: Spencer Date: Mon, 11 Oct 2021 18:29:10 -0500 Subject: [PATCH 26/73] [ftr] ensure indentation is reset between configs (#114359) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../src/tooling_log/tooling_log.test.ts | 28 ++++++++++ .../src/tooling_log/tooling_log.ts | 37 +++++++++++-- packages/kbn-pm/dist/index.js | 40 ++++++++++++-- .../src/functional_test_runner/cli.ts | 2 +- .../kbn-test/src/functional_tests/tasks.ts | 54 +++++++++---------- 5 files changed, 121 insertions(+), 40 deletions(-) diff --git a/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts b/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts index 2a1099587d0c4..ec63a9fb7e6f2 100644 --- a/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts +++ b/packages/kbn-dev-utils/src/tooling_log/tooling_log.test.ts @@ -12,6 +12,10 @@ import { toArray, takeUntil } from 'rxjs/operators'; import { ToolingLog } from './tooling_log'; import { Writer } from './writer'; import { ToolingLogTextWriter } from './tooling_log_text_writer'; +import { ToolingLogCollectingWriter } from './tooling_log_collecting_writer'; +import { createStripAnsiSerializer } from '../serializers/strip_ansi_serializer'; + +expect.addSnapshotSerializer(createStripAnsiSerializer()); it('creates zero writers without a config', () => { const log = new ToolingLog(); @@ -67,6 +71,30 @@ describe('#indent()', () => { expect(write.mock.calls).toMatchSnapshot(); }); + + it('resets the indentation after block executes and promise resolves', async () => { + const log = new ToolingLog(); + const writer = new ToolingLogCollectingWriter(); + log.setWriters([writer]); + + log.info('base'); + await log.indent(2, async () => { + log.indent(2); + log.info('hello'); + log.indent(2); + log.info('world'); + }); + log.info('back to base'); + + expect(writer.messages).toMatchInlineSnapshot(` + Array [ + " info base", + " │ info hello", + " │ info world", + " info back to base", + ] + `); + }); }); (['verbose', 'debug', 'info', 'success', 'warning', 'error', 'write'] as const).forEach( diff --git a/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts b/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts index d60bf9bcb1d70..e9fd15afefe4e 100644 --- a/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts +++ b/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts @@ -13,7 +13,7 @@ import { Writer } from './writer'; import { Message, MessageTypes } from './message'; export class ToolingLog { - private identWidth = 0; + private indentWidth = 0; private writers: Writer[]; private readonly written$: Rx.Subject; @@ -22,9 +22,36 @@ export class ToolingLog { this.written$ = new Rx.Subject(); } - public indent(delta = 0) { - this.identWidth = Math.max(this.identWidth + delta, 0); - return this.identWidth; + /** + * Get the current indentation level of the ToolingLog + */ + public getIndent() { + return this.indentWidth; + } + + /** + * Indent the output of the ToolingLog by some character (4 is a good choice usually). + * + * If provided, the `block` function will be executed and once it's promise is resolved + * or rejected the indentation will be reset to its original state. + * + * @param delta the number of spaces to increase/decrease the indentation + * @param block a function to run and reset any indentation changes after + */ + public indent(delta = 0, block?: () => Promise) { + const originalWidth = this.indentWidth; + this.indentWidth = Math.max(this.indentWidth + delta, 0); + if (!block) { + return; + } + + return (async () => { + try { + return await block(); + } finally { + this.indentWidth = originalWidth; + } + })(); } public verbose(...args: any[]) { @@ -70,7 +97,7 @@ export class ToolingLog { private sendToWriters(type: MessageTypes, args: any[]) { const msg = { type, - indent: this.identWidth, + indent: this.indentWidth, args, }; diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index f395636379141..a231fe21ea838 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -626,16 +626,46 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && */ class ToolingLog { constructor(writerConfig) { - (0, _defineProperty2.default)(this, "identWidth", 0); + (0, _defineProperty2.default)(this, "indentWidth", 0); (0, _defineProperty2.default)(this, "writers", void 0); (0, _defineProperty2.default)(this, "written$", void 0); this.writers = writerConfig ? [new _tooling_log_text_writer.ToolingLogTextWriter(writerConfig)] : []; this.written$ = new Rx.Subject(); } + /** + * Get the current indentation level of the ToolingLog + */ + + + getIndent() { + return this.indentWidth; + } + /** + * Indent the output of the ToolingLog by some character (4 is a good choice usually). + * + * If provided, the `block` function will be executed and once it's promise is resolved + * or rejected the indentation will be reset to its original state. + * + * @param delta the number of spaces to increase/decrease the indentation + * @param block a function to run and reset any indentation changes after + */ - indent(delta = 0) { - this.identWidth = Math.max(this.identWidth + delta, 0); - return this.identWidth; + + indent(delta = 0, block) { + const originalWidth = this.indentWidth; + this.indentWidth = Math.max(this.indentWidth + delta, 0); + + if (!block) { + return; + } + + return (async () => { + try { + return await block(); + } finally { + this.indentWidth = originalWidth; + } + })(); } verbose(...args) { @@ -681,7 +711,7 @@ class ToolingLog { sendToWriters(type, args) { const msg = { type, - indent: this.identWidth, + indent: this.indentWidth, args }; let written = false; diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli.ts index 3ad365a028b65..d9938bebea5bb 100644 --- a/packages/kbn-test/src/functional_test_runner/cli.ts +++ b/packages/kbn-test/src/functional_test_runner/cli.ts @@ -79,7 +79,7 @@ export function runFtrCli() { err: err.message, ...flags, }); - log.indent(-log.indent()); + log.indent(-log.getIndent()); log.error(err); process.exitCode = 1; } else { diff --git a/packages/kbn-test/src/functional_tests/tasks.ts b/packages/kbn-test/src/functional_tests/tasks.ts index 3bc697c143f40..c8265c032cbcc 100644 --- a/packages/kbn-test/src/functional_tests/tasks.ts +++ b/packages/kbn-test/src/functional_tests/tasks.ts @@ -78,12 +78,9 @@ export async function runTests(options: RunTestsParams) { log.write('--- asserting that all tests belong to a ciGroup'); for (const configPath of options.configs) { log.info('loading', configPath); - log.indent(4); - try { + await log.indent(4, async () => { await assertNoneExcluded({ configPath, options: { ...options, log } }); - } finally { - log.indent(-4); - } + }); continue; } @@ -94,42 +91,41 @@ export async function runTests(options: RunTestsParams) { const configPathsWithTests: string[] = []; for (const configPath of options.configs) { log.info('testing', configPath); - log.indent(4); - try { + await log.indent(4, async () => { if (await hasTests({ configPath, options: { ...options, log } })) { configPathsWithTests.push(configPath); } - } finally { - log.indent(-4); - } + }); } for (const configPath of configPathsWithTests) { - log.write(`--- Running ${relative(REPO_ROOT, configPath)}`); + await log.indent(0, async () => { + log.write(`--- Running ${relative(REPO_ROOT, configPath)}`); - await withProcRunner(log, async (procs) => { - const config = await readConfigFile(log, configPath); + await withProcRunner(log, async (procs) => { + const config = await readConfigFile(log, configPath); - let es; - try { - es = await runElasticsearch({ config, options: { ...options, log } }); - await runKibanaServer({ procs, config, options }); - await runFtr({ configPath, options: { ...options, log } }); - } finally { + let es; try { - const delay = config.get('kbnTestServer.delayShutdown'); - if (typeof delay === 'number') { - log.info('Delaying shutdown of Kibana for', delay, 'ms'); - await new Promise((r) => setTimeout(r, delay)); - } - - await procs.stop('kibana'); + es = await runElasticsearch({ config, options: { ...options, log } }); + await runKibanaServer({ procs, config, options }); + await runFtr({ configPath, options: { ...options, log } }); } finally { - if (es) { - await es.cleanup(); + try { + const delay = config.get('kbnTestServer.delayShutdown'); + if (typeof delay === 'number') { + log.info('Delaying shutdown of Kibana for', delay, 'ms'); + await new Promise((r) => setTimeout(r, delay)); + } + + await procs.stop('kibana'); + } finally { + if (es) { + await es.cleanup(); + } } } - } + }); }); } } From 8e72e17648dbfd4d6c3af527edc0daea9e6c6b36 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Mon, 11 Oct 2021 19:46:01 -0400 Subject: [PATCH 27/73] api docs (#114565) --- api_docs/apm.json | 290 +++--- api_docs/apm.mdx | 2 +- api_docs/charts.json | 945 +++++++++++++++++- api_docs/charts.mdx | 8 +- api_docs/core.json | 262 ++++- api_docs/core.mdx | 2 +- api_docs/core_application.json | 2 +- api_docs/core_application.mdx | 2 +- api_docs/core_chrome.mdx | 2 +- api_docs/core_http.json | 2 +- api_docs/core_http.mdx | 2 +- api_docs/core_saved_objects.json | 8 +- api_docs/core_saved_objects.mdx | 2 +- api_docs/dashboard.json | 6 +- api_docs/dashboard_enhanced.json | 10 +- api_docs/data.json | 735 ++++++++------ api_docs/data.mdx | 2 +- api_docs/data_autocomplete.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.json | 10 +- api_docs/data_search.mdx | 2 +- api_docs/data_ui.mdx | 2 +- api_docs/data_views.json | 345 +++++-- api_docs/data_views.mdx | 2 +- api_docs/deprecations_by_api.mdx | 4 +- api_docs/deprecations_by_plugin.mdx | 28 +- api_docs/elastic_apm_generator.json | 257 +++++ api_docs/elastic_apm_generator.mdx | 27 + api_docs/event_log.json | 22 +- api_docs/expression_metric_vis.json | 837 ++++++++++++++++ api_docs/expression_metric_vis.mdx | 33 + api_docs/fleet.json | 816 +++++++++++++-- api_docs/fleet.mdx | 2 +- api_docs/interactive_setup.json | 98 ++ api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_config.json | 212 +++- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_es_query.json | 370 ++++--- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_logging.json | 2 +- api_docs/kbn_monaco.json | 166 ++- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_optimizer.json | 55 + api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.json | 4 +- api_docs/kbn_typed_react_router_config.json | 125 ++- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kibana_utils.json | 48 +- api_docs/kibana_utils.mdx | 2 +- api_docs/lens.json | 13 + api_docs/lens.mdx | 2 +- api_docs/maps.json | 4 +- api_docs/observability.json | 238 ++++- api_docs/observability.mdx | 2 +- api_docs/plugin_directory.mdx | 47 +- api_docs/saved_objects.json | 8 - api_docs/security_solution.json | 269 +++-- api_docs/security_solution.mdx | 2 +- api_docs/share.json | 111 +- api_docs/share.mdx | 2 +- api_docs/spaces.json | 91 +- api_docs/spaces.mdx | 2 +- api_docs/timelines.json | 106 +- api_docs/transform.json | 101 ++ api_docs/transform.mdx | 37 + api_docs/vis_default_editor.json | 8 +- api_docs/vis_type_vislib.json | 4 +- api_docs/vis_type_xy.json | 8 +- api_docs/visualizations.json | 500 ++++++++- api_docs/visualizations.mdx | 2 +- .../tests/snapshots/plugin_a.foo.json | 76 -- .../api_docs/tests/snapshots/plugin_a.foo.mdx | 35 - 72 files changed, 6206 insertions(+), 1229 deletions(-) create mode 100644 api_docs/elastic_apm_generator.json create mode 100644 api_docs/elastic_apm_generator.mdx create mode 100644 api_docs/expression_metric_vis.json create mode 100644 api_docs/expression_metric_vis.mdx create mode 100644 api_docs/transform.json create mode 100644 api_docs/transform.mdx delete mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.json delete mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.mdx diff --git a/api_docs/apm.json b/api_docs/apm.json index c2300232f9b8f..8b43370097091 100644 --- a/api_docs/apm.json +++ b/api_docs/apm.json @@ -184,7 +184,7 @@ "APMPluginStartDependencies", ", unknown>, plugins: Pick<", "APMPluginSetupDependencies", - ", \"data\" | \"cloud\" | \"security\" | \"home\" | \"features\" | \"fleet\" | \"ml\" | \"actions\" | \"usageCollection\" | \"apmOss\" | \"licensing\" | \"observability\" | \"ruleRegistry\" | \"spaces\" | \"taskManager\" | \"alerting\">) => { config$: ", + ", \"data\" | \"cloud\" | \"security\" | \"home\" | \"features\" | \"fleet\" | \"ml\" | \"actions\" | \"usageCollection\" | \"spaces\" | \"apmOss\" | \"licensing\" | \"observability\" | \"ruleRegistry\" | \"taskManager\" | \"alerting\">) => { config$: ", "Observable", "<{ 'apm_oss.transactionIndices': string; 'apm_oss.spanIndices': string; 'apm_oss.errorIndices': string; 'apm_oss.metricsIndices': string; 'apm_oss.sourcemapIndices': string; 'apm_oss.onboardingIndices': string; 'xpack.apm.serviceMapEnabled': boolean; 'xpack.apm.serviceMapFingerprintBucketSize': number; 'xpack.apm.serviceMapTraceIdBucketSize': number; 'xpack.apm.serviceMapFingerprintGlobalBucketSize': number; 'xpack.apm.serviceMapTraceIdGlobalBucketSize': number; 'xpack.apm.serviceMapMaxTracesPerRequest': number; 'xpack.apm.ui.enabled': boolean; 'xpack.apm.ui.maxTraceItems': number; 'xpack.apm.ui.transactionGroupBucketSize': number; 'xpack.apm.autocreateApmIndexPattern': boolean; 'xpack.apm.telemetryCollectionEnabled': boolean; 'xpack.apm.searchAggregatedTransactions': ", "SearchAggregatedTransactionSetting", @@ -248,7 +248,7 @@ "signature": [ "Pick<", "APMPluginSetupDependencies", - ", \"data\" | \"cloud\" | \"security\" | \"home\" | \"features\" | \"fleet\" | \"ml\" | \"actions\" | \"usageCollection\" | \"apmOss\" | \"licensing\" | \"observability\" | \"ruleRegistry\" | \"spaces\" | \"taskManager\" | \"alerting\">" + ", \"data\" | \"cloud\" | \"security\" | \"home\" | \"features\" | \"fleet\" | \"ml\" | \"actions\" | \"usageCollection\" | \"spaces\" | \"apmOss\" | \"licensing\" | \"observability\" | \"ruleRegistry\" | \"taskManager\" | \"alerting\">" ], "path": "x-pack/plugins/apm/server/plugin.ts", "deprecated": false, @@ -797,7 +797,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /api/apm/index_pattern/static\" | \"GET /api/apm/index_pattern/dynamic\" | \"GET /api/apm/environments\" | \"GET /api/apm/services/{serviceName}/errors\" | \"GET /api/apm/services/{serviceName}/errors/{groupId}\" | \"GET /api/apm/services/{serviceName}/errors/distribution\" | \"GET /api/apm/services/{serviceName}/metrics/charts\" | \"GET /api/apm/observability_overview\" | \"GET /api/apm/observability_overview/has_data\" | \"GET /api/apm/rum/client-metrics\" | \"GET /api/apm/rum-client/page-load-distribution\" | \"GET /api/apm/rum-client/page-load-distribution/breakdown\" | \"GET /api/apm/rum-client/page-view-trends\" | \"GET /api/apm/rum-client/services\" | \"GET /api/apm/rum-client/visitor-breakdown\" | \"GET /api/apm/rum-client/web-core-vitals\" | \"GET /api/apm/rum-client/long-task-metrics\" | \"GET /api/apm/rum-client/url-search\" | \"GET /api/apm/rum-client/js-errors\" | \"GET /api/apm/observability_overview/has_rum_data\" | \"GET /api/apm/service-map\" | \"GET /api/apm/service-map/service/{serviceName}\" | \"GET /api/apm/service-map/backend/{backendName}\" | \"GET /api/apm/services/{serviceName}/serviceNodes\" | \"GET /api/apm/services\" | \"GET /api/apm/services/detailed_statistics\" | \"GET /api/apm/services/{serviceName}/metadata/details\" | \"GET /api/apm/services/{serviceName}/metadata/icons\" | \"GET /api/apm/services/{serviceName}/agent\" | \"GET /api/apm/services/{serviceName}/transaction_types\" | \"GET /api/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /api/apm/services/{serviceName}/error_groups/main_statistics\" | \"GET /api/apm/services/{serviceName}/error_groups/detailed_statistics\" | \"GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /api/apm/services/{serviceName}/throughput\" | \"GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /api/apm/services/{serviceName}/dependencies\" | \"GET /api/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /api/apm/services/{serviceName}/profiling/timeline\" | \"GET /api/apm/services/{serviceName}/profiling/statistics\" | \"GET /api/apm/services/{serviceName}/alerts\" | \"GET /api/apm/services/{serviceName}/infrastructure\" | \"GET /internal/apm/suggestions\" | \"GET /api/apm/traces/{traceId}\" | \"GET /api/apm/traces\" | \"GET /api/apm/traces/{traceId}/root_transaction\" | \"GET /api/apm/transactions/{transactionId}\" | \"GET /api/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /api/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /api/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /api/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /api/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /api/apm/alerts/chart_preview/transaction_error_rate\" | \"GET /api/apm/alerts/chart_preview/transaction_duration\" | \"GET /api/apm/alerts/chart_preview/transaction_error_count\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/services\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /api/apm/settings/anomaly-detection/jobs\" | \"POST /api/apm/settings/anomaly-detection/jobs\" | \"GET /api/apm/settings/anomaly-detection/environments\" | \"GET /api/apm/settings/apm-index-settings\" | \"GET /api/apm/settings/apm-indices\" | \"POST /api/apm/settings/apm-indices/save\" | \"GET /api/apm/settings/custom_links/transaction\" | \"GET /api/apm/settings/custom_links\" | \"POST /api/apm/settings/custom_links\" | \"PUT /api/apm/settings/custom_links/{id}\" | \"DELETE /api/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /api/apm/fleet/has_data\" | \"GET /api/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /api/apm/fleet/apm_server_schema/unsupported\" | \"GET /api/apm/fleet/migration_check\" | \"POST /api/apm/fleet/cloud_apm_package_policy\" | \"GET /api/apm/backends/top_backends\" | \"GET /api/apm/backends/{backendName}/upstream_services\" | \"GET /api/apm/backends/{backendName}/metadata\" | \"GET /api/apm/backends/{backendName}/charts/latency\" | \"GET /api/apm/backends/{backendName}/charts/throughput\" | \"GET /api/apm/backends/{backendName}/charts/error_rate\" | \"GET /api/apm/fallback_to_transactions\" | \"GET /api/apm/has_data\" | \"GET /api/apm/event_metadata/{processorEvent}/{id}\"" + "\"POST /internal/apm/index_pattern/static\" | \"GET /internal/apm/index_pattern/dynamic\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /api/apm/rum/client-metrics\" | \"GET /api/apm/rum-client/page-load-distribution\" | \"GET /api/apm/rum-client/page-load-distribution/breakdown\" | \"GET /api/apm/rum-client/page-view-trends\" | \"GET /api/apm/rum-client/services\" | \"GET /api/apm/rum-client/visitor-breakdown\" | \"GET /api/apm/rum-client/web-core-vitals\" | \"GET /api/apm/rum-client/long-task-metrics\" | \"GET /api/apm/rum-client/url-search\" | \"GET /api/apm/rum-client/js-errors\" | \"GET /api/apm/observability_overview/has_rum_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/backend/{backendName}\" | \"GET /internal/apm/services/{serviceName}/serviceNodes\" | \"GET /internal/apm/services\" | \"GET /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/error_groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/profiling/timeline\" | \"GET /internal/apm/services/{serviceName}/profiling/statistics\" | \"GET /internal/apm/services/{serviceName}/alerts\" | \"GET /internal/apm/services/{serviceName}/infrastructure\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_duration\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_count\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/services\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_data\" | \"GET /internal/apm/fleet/agents\" | \"POST /internal/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/backends/top_backends\" | \"GET /internal/apm/backends/{backendName}/upstream_services\" | \"GET /internal/apm/backends/{backendName}/metadata\" | \"GET /internal/apm/backends/{backendName}/charts/latency\" | \"GET /internal/apm/backends/{backendName}/charts/throughput\" | \"GET /internal/apm/backends/{backendName}/charts/error_rate\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\"" ], "path": "x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -858,7 +858,7 @@ }, ", ", "APMRouteCreateOptions", - ", { \"POST /api/apm/index_pattern/static\": ", + ", { \"POST /internal/apm/index_pattern/static\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -866,7 +866,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/index_pattern/static\", undefined, ", + "<\"POST /internal/apm/index_pattern/static\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -876,7 +876,7 @@ }, ", { created: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/index_pattern/dynamic\": ", + ">; } & { \"GET /internal/apm/index_pattern/dynamic\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -884,7 +884,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/index_pattern/dynamic\", undefined, ", + "<\"GET /internal/apm/index_pattern/dynamic\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -896,7 +896,7 @@ "IndexPatternTitleAndFields", " | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/environments\": ", + ">; } & { \"GET /internal/apm/environments\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -904,7 +904,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/environments\", ", + "<\"GET /internal/apm/environments\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -928,7 +928,7 @@ }, ", { environments: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/errors\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/errors\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -936,7 +936,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/errors\", ", + "<\"GET /internal/apm/services/{serviceName}/errors\", ", "TypeC", "<{ path: ", "TypeC", @@ -988,7 +988,7 @@ }, ", { errorGroups: { message: string; occurrenceCount: number; culprit: string | undefined; groupId: string; latestOccurrenceAt: string; handled: boolean | undefined; type: string | undefined; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/errors/{groupId}\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/errors/{groupId}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -996,7 +996,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/errors/{groupId}\", ", + "<\"GET /internal/apm/services/{serviceName}/errors/{groupId}\", ", "TypeC", "<{ path: ", "TypeC", @@ -1044,7 +1044,7 @@ "APMError", "; occurrencesCount: number; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/errors/distribution\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/errors/distribution\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1052,7 +1052,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/errors/distribution\", ", + "<\"GET /internal/apm/services/{serviceName}/errors/distribution\", ", "TypeC", "<{ path: ", "TypeC", @@ -1098,7 +1098,7 @@ }, ", { noHits: boolean; buckets: { key: number; count: number; }[]; bucketSize: number; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/metrics/charts\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/metrics/charts\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1106,7 +1106,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/metrics/charts\", ", + "<\"GET /internal/apm/services/{serviceName}/metrics/charts\", ", "TypeC", "<{ path: ", "TypeC", @@ -1158,7 +1158,7 @@ "MetricsChartsByAgentAPIResponse", ", ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/observability_overview\": ", + ">; } & { \"GET /internal/apm/observability_overview\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1166,7 +1166,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/observability_overview\", ", + "<\"GET /internal/apm/observability_overview\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1190,7 +1190,7 @@ }, ", { serviceCount: number; transactionPerMinute: { value: undefined; timeseries: never[]; } | { value: number; timeseries: { x: number; y: number | null; }[]; }; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/observability_overview/has_data\": ", + ">; } & { \"GET /internal/apm/observability_overview/has_data\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1198,7 +1198,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/observability_overview/has_data\", undefined, ", + "<\"GET /internal/apm/observability_overview/has_data\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -1642,7 +1642,7 @@ }, ", { indices: string; hasData: boolean; serviceName: string | number | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/service-map\": ", + ">; } & { \"GET /internal/apm/service-map\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1650,7 +1650,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/service-map\", ", + "<\"GET /internal/apm/service-map\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1692,7 +1692,7 @@ "ServiceAnomalyStats", " | undefined; label: string | undefined; id?: string | undefined; parent?: string | undefined; position?: cytoscape.Position | undefined; } | { 'span.destination.service.resource': string; 'span.type': string; 'span.subtype': string; label: string | undefined; id?: string | undefined; parent?: string | undefined; position?: cytoscape.Position | undefined; } | { id: string; source: string | undefined; target: string | undefined; label: string | undefined; bidirectional?: boolean | undefined; isInverseEdge?: boolean | undefined; } | undefined)[]; }; } | { data: { id: string; source: string; target: string; }; })[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/service-map/service/{serviceName}\": ", + ">; } & { \"GET /internal/apm/service-map/service/{serviceName}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1700,7 +1700,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/service-map/service/{serviceName}\", ", + "<\"GET /internal/apm/service-map/service/{serviceName}\", ", "TypeC", "<{ path: ", "TypeC", @@ -1738,7 +1738,7 @@ }, ", { avgMemoryUsage: number | null; avgCpuUsage: number | null; transactionStats: { avgTransactionDuration: number | null; avgRequestsPerMinute: number | null; }; avgErrorRate: number | null; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/service-map/backend/{backendName}\": ", + ">; } & { \"GET /internal/apm/service-map/backend/{backendName}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1746,7 +1746,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/service-map/backend/{backendName}\", ", + "<\"GET /internal/apm/service-map/backend/{backendName}\", ", "TypeC", "<{ path: ", "TypeC", @@ -1784,7 +1784,7 @@ }, ", { avgErrorRate: null; transactionStats: { avgRequestsPerMinute: null; avgTransactionDuration: null; }; } | { avgErrorRate: number; transactionStats: { avgRequestsPerMinute: number; avgTransactionDuration: number; }; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/serviceNodes\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/serviceNodes\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1792,7 +1792,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/serviceNodes\", ", + "<\"GET /internal/apm/services/{serviceName}/serviceNodes\", ", "TypeC", "<{ path: ", "TypeC", @@ -1834,7 +1834,7 @@ }, ", { serviceNodes: { name: string; cpu: number | null; heapMemory: number | null; hostName: string | null | undefined; nonHeapMemory: number | null; threadCount: number | null; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services\": ", + ">; } & { \"GET /internal/apm/services\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1842,7 +1842,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services\", ", + "<\"GET /internal/apm/services\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1892,7 +1892,7 @@ "ServiceHealthStatus", "; }>; hasLegacyData: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/detailed_statistics\": ", + ">; } & { \"GET /internal/apm/services/detailed_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1900,7 +1900,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/detailed_statistics\", ", + "<\"GET /internal/apm/services/detailed_statistics\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1946,7 +1946,7 @@ }, ", { currentPeriod: _.Dictionary<{ serviceName: string; latency: { x: number; y: number | null; }[]; transactionErrorRate: { x: number; y: number; }[]; throughput: { x: number; y: number; }[]; }>; previousPeriod: _.Dictionary<{ serviceName: string; latency: { x: number; y: number | null; }[]; transactionErrorRate: { x: number; y: number; }[]; throughput: { x: number; y: number; }[]; }>; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/metadata/details\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/metadata/details\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1954,7 +1954,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/metadata/details\", ", + "<\"GET /internal/apm/services/{serviceName}/metadata/details\", ", "TypeC", "<{ path: ", "TypeC", @@ -1978,7 +1978,7 @@ "ServiceMetadataDetails", ", ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/metadata/icons\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/metadata/icons\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1986,7 +1986,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/metadata/icons\", ", + "<\"GET /internal/apm/services/{serviceName}/metadata/icons\", ", "TypeC", "<{ path: ", "TypeC", @@ -2010,7 +2010,7 @@ "ServiceMetadataIcons", ", ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/agent\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/agent\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2018,7 +2018,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/agent\", ", + "<\"GET /internal/apm/services/{serviceName}/agent\", ", "TypeC", "<{ path: ", "TypeC", @@ -2040,7 +2040,7 @@ }, ", { agentName?: undefined; runtimeName?: undefined; } | { agentName: string | undefined; runtimeName: string | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transaction_types\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transaction_types\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2048,7 +2048,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transaction_types\", ", + "<\"GET /internal/apm/services/{serviceName}/transaction_types\", ", "TypeC", "<{ path: ", "TypeC", @@ -2070,7 +2070,7 @@ }, ", { transactionTypes: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/node/{serviceNodeName}/metadata\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2078,7 +2078,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/node/{serviceNodeName}/metadata\", ", + "<\"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\", ", "TypeC", "<{ path: ", "TypeC", @@ -2206,7 +2206,7 @@ "Annotation", "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/error_groups/main_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/error_groups/main_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2214,7 +2214,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/error_groups/main_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/error_groups/main_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -2260,7 +2260,7 @@ }, ", { is_aggregation_accurate: boolean; error_groups: { group_id: string; name: string; lastSeen: number; occurrences: number; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/error_groups/detailed_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2268,7 +2268,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/error_groups/detailed_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -2326,7 +2326,7 @@ "Coordinate", "[]; }>; previousPeriod: _.Dictionary<{ timeseries: { x: number; y: number | null | undefined; }[]; groupId: string; }>; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2334,7 +2334,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\", ", + "<\"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\", ", "TypeC", "<{ path: ", "TypeC", @@ -2380,7 +2380,7 @@ "Cloud", " | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/throughput\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/throughput\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2388,7 +2388,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/throughput\", ", + "<\"GET /internal/apm/services/{serviceName}/throughput\", ", "TypeC", "<{ path: ", "TypeC", @@ -2448,7 +2448,7 @@ "ThroughputUnit", "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2456,7 +2456,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -2522,7 +2522,7 @@ }, ", { currentPeriod: { serviceNodeName: string; errorRate?: number | undefined; latency?: number | undefined; throughput?: number | undefined; cpuUsage?: number | null | undefined; memoryUsage?: number | null | undefined; }[]; previousPeriod: { serviceNodeName: string; errorRate?: number | undefined; latency?: number | undefined; throughput?: number | undefined; cpuUsage?: number | null | undefined; memoryUsage?: number | null | undefined; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2530,7 +2530,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -2610,7 +2610,7 @@ "Coordinate", "[] | undefined; }>; previousPeriod: _.Dictionary<{ cpuUsage: { x: number; y: number | null | undefined; }[]; errorRate: { x: number; y: number | null | undefined; }[]; latency: { x: number; y: number | null | undefined; }[]; memoryUsage: { x: number; y: number | null | undefined; }[]; throughput: { x: number; y: number | null | undefined; }[]; serviceNodeName: string; }>; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/dependencies\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/dependencies\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2618,7 +2618,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/dependencies\", ", + "<\"GET /internal/apm/services/{serviceName}/dependencies\", ", "TypeC", "<{ path: ", "TypeC", @@ -2682,7 +2682,7 @@ "Node", "; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/dependencies/breakdown\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2690,7 +2690,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/dependencies/breakdown\", ", + "<\"GET /internal/apm/services/{serviceName}/dependencies/breakdown\", ", "TypeC", "<{ path: ", "TypeC", @@ -2732,7 +2732,7 @@ }, ", { breakdown: { title: string; data: { x: number; y: number; }[]; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/profiling/timeline\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/profiling/timeline\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2740,7 +2740,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/profiling/timeline\", ", + "<\"GET /internal/apm/services/{serviceName}/profiling/timeline\", ", "TypeC", "<{ path: ", "TypeC", @@ -2782,7 +2782,7 @@ }, ", { profilingTimeline: { x: number; valueTypes: { wall_time: number; cpu_time: number; samples: number; alloc_objects: number; alloc_space: number; inuse_objects: number; inuse_space: number; unknown: number; }; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/profiling/statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/profiling/statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2790,7 +2790,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/profiling/statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/profiling/statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -2866,7 +2866,7 @@ "ProfileNode", ">; rootNodes: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/alerts\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/alerts\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2874,7 +2874,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/alerts\", ", + "<\"GET /internal/apm/services/{serviceName}/alerts\", ", "TypeC", "<{ path: ", "TypeC", @@ -2916,7 +2916,7 @@ }, ", { alerts: Partial>[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/infrastructure\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/infrastructure\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -2924,7 +2924,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/infrastructure\", ", + "<\"GET /internal/apm/services/{serviceName}/infrastructure\", ", "TypeC", "<{ path: ", "TypeC", @@ -2992,7 +2992,7 @@ }, ", { terms: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/traces/{traceId}\": ", + ">; } & { \"GET /internal/apm/traces/{traceId}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3000,7 +3000,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/traces/{traceId}\", ", + "<\"GET /internal/apm/traces/{traceId}\", ", "TypeC", "<{ path: ", "TypeC", @@ -3028,7 +3028,7 @@ "APMError", "[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/traces\": ", + ">; } & { \"GET /internal/apm/traces\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3036,7 +3036,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/traces\", ", + "<\"GET /internal/apm/traces\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3076,7 +3076,7 @@ "TransactionGroup", "[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/traces/{traceId}/root_transaction\": ", + ">; } & { \"GET /internal/apm/traces/{traceId}/root_transaction\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3084,7 +3084,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/traces/{traceId}/root_transaction\", ", + "<\"GET /internal/apm/traces/{traceId}/root_transaction\", ", "TypeC", "<{ path: ", "TypeC", @@ -3102,7 +3102,7 @@ "Transaction", "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/transactions/{transactionId}\": ", + ">; } & { \"GET /internal/apm/transactions/{transactionId}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3110,7 +3110,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/transactions/{transactionId}\", ", + "<\"GET /internal/apm/transactions/{transactionId}\", ", "TypeC", "<{ path: ", "TypeC", @@ -3128,7 +3128,7 @@ "Transaction", "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transactions/groups/main_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3136,7 +3136,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transactions/groups/main_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -3196,7 +3196,7 @@ }, ", { transactionGroups: { transactionType: string; name: string; latency: number | null; throughput: number; errorRate: number; impact: number; }[]; isAggregationAccurate: boolean; bucketSize: number; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3204,7 +3204,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics\", ", + "<\"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\", ", "TypeC", "<{ path: ", "TypeC", @@ -3280,7 +3280,7 @@ "Coordinate", "[]; impact: number; }>; previousPeriod: _.Dictionary<{ errorRate: { x: number; y: number | null | undefined; }[]; throughput: { x: number; y: number | null | undefined; }[]; latency: { x: number; y: number | null | undefined; }[]; transactionName: string; impact: number; }>; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transactions/charts/latency\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3288,7 +3288,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transactions/charts/latency\", ", + "<\"GET /internal/apm/services/{serviceName}/transactions/charts/latency\", ", "TypeC", "<{ path: ", "TypeC", @@ -3360,7 +3360,7 @@ }, ", { currentPeriod: { overallAvgDuration: number | null; latencyTimeseries: { x: number; y: number | null; }[]; }; previousPeriod: { latencyTimeseries: { x: number; y: number | null | undefined; }[]; overallAvgDuration: number | null; }; anomalyTimeseries: { jobId: string; anomalyScore: { x0: number; x: number; y: number; }[]; anomalyBoundaries: { x: number; y0: number; y: number; }[]; } | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transactions/traces/samples\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3368,7 +3368,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transactions/traces/samples\", ", + "<\"GET /internal/apm/services/{serviceName}/transactions/traces/samples\", ", "TypeC", "<{ path: ", "TypeC", @@ -3426,7 +3426,7 @@ }, ", { noHits: boolean; traceSamples: { transactionId: string; traceId: string; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transaction/charts/breakdown\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3434,7 +3434,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transaction/charts/breakdown\", ", + "<\"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\", ", "TypeC", "<{ path: ", "TypeC", @@ -3484,7 +3484,7 @@ }, ", { timeseries: { title: string; color: string; type: string; data: { x: number; y: number | null; }[]; hideLegend: boolean; legendValue: string; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/services/{serviceName}/transactions/charts/error_rate\": ", + ">; } & { \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3492,7 +3492,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/services/{serviceName}/transactions/charts/error_rate\", ", + "<\"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\", ", "TypeC", "<{ path: ", "TypeC", @@ -3552,7 +3552,7 @@ "Coordinate", "[]; average: number | null; }; previousPeriod: { transactionErrorRate: { x: number; y: number | null | undefined; }[]; noHits: boolean; average: number | null; }; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/alerts/chart_preview/transaction_error_rate\": ", + ">; } & { \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3560,7 +3560,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/alerts/chart_preview/transaction_error_rate\", ", + "<\"GET /internal/apm/alerts/chart_preview/transaction_error_rate\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3612,7 +3612,7 @@ }, ", { errorRateChartPreview: { x: number; y: number; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/alerts/chart_preview/transaction_duration\": ", + ">; } & { \"GET /internal/apm/alerts/chart_preview/transaction_duration\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3620,7 +3620,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/alerts/chart_preview/transaction_duration\", ", + "<\"GET /internal/apm/alerts/chart_preview/transaction_duration\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3672,7 +3672,7 @@ }, ", { latencyChartPreview: { x: number; y: number | null; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/alerts/chart_preview/transaction_error_count\": ", + ">; } & { \"GET /internal/apm/alerts/chart_preview/transaction_error_count\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3680,7 +3680,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/alerts/chart_preview/transaction_error_count\", ", + "<\"GET /internal/apm/alerts/chart_preview/transaction_error_count\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3968,7 +3968,7 @@ }, ", { agentName: string | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/anomaly-detection/jobs\": ", + ">; } & { \"GET /internal/apm/settings/anomaly-detection/jobs\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3976,7 +3976,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/anomaly-detection/jobs\", undefined, ", + "<\"GET /internal/apm/settings/anomaly-detection/jobs\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -3986,7 +3986,7 @@ }, ", { jobs: { job_id: string; environment: string; }[]; hasLegacyJobs: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"POST /api/apm/settings/anomaly-detection/jobs\": ", + ">; } & { \"POST /internal/apm/settings/anomaly-detection/jobs\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -3994,7 +3994,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/settings/anomaly-detection/jobs\", ", + "<\"POST /internal/apm/settings/anomaly-detection/jobs\", ", "TypeC", "<{ body: ", "TypeC", @@ -4012,7 +4012,7 @@ }, ", { jobCreated: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/anomaly-detection/environments\": ", + ">; } & { \"GET /internal/apm/settings/anomaly-detection/environments\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4020,7 +4020,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/anomaly-detection/environments\", undefined, ", + "<\"GET /internal/apm/settings/anomaly-detection/environments\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4030,7 +4030,7 @@ }, ", { environments: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/apm-index-settings\": ", + ">; } & { \"GET /internal/apm/settings/apm-index-settings\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4038,7 +4038,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/apm-index-settings\", undefined, ", + "<\"GET /internal/apm/settings/apm-index-settings\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4048,7 +4048,7 @@ }, ", { apmIndexSettings: { configurationName: \"apm_oss.sourcemapIndices\" | \"apm_oss.errorIndices\" | \"apm_oss.onboardingIndices\" | \"apm_oss.spanIndices\" | \"apm_oss.transactionIndices\" | \"apm_oss.metricsIndices\" | \"apmAgentConfigurationIndex\" | \"apmCustomLinkIndex\"; defaultValue: string; savedValue: string | undefined; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/apm-indices\": ", + ">; } & { \"GET /internal/apm/settings/apm-indices\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4056,7 +4056,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/apm-indices\", undefined, ", + "<\"GET /internal/apm/settings/apm-indices\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4068,7 +4068,7 @@ "ApmIndicesConfig", ", ", "APMRouteCreateOptions", - ">; } & { \"POST /api/apm/settings/apm-indices/save\": ", + ">; } & { \"POST /internal/apm/settings/apm-indices/save\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4076,7 +4076,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/settings/apm-indices/save\", ", + "<\"POST /internal/apm/settings/apm-indices/save\", ", "TypeC", "<{ body: ", "PartialC", @@ -4104,7 +4104,7 @@ "SavedObject", "<{}>, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/custom_links/transaction\": ", + ">; } & { \"GET /internal/apm/settings/custom_links/transaction\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4112,7 +4112,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/custom_links/transaction\", ", + "<\"GET /internal/apm/settings/custom_links/transaction\", ", "PartialC", "<{ query: ", "PartialC", @@ -4136,7 +4136,7 @@ "Transaction", ", ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/settings/custom_links\": ", + ">; } & { \"GET /internal/apm/settings/custom_links\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4144,7 +4144,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/settings/custom_links\", ", + "<\"GET /internal/apm/settings/custom_links\", ", "PartialC", "<{ query: ", "PartialC", @@ -4168,7 +4168,7 @@ "CustomLink", "[]; }, ", "APMRouteCreateOptions", - ">; } & { \"POST /api/apm/settings/custom_links\": ", + ">; } & { \"POST /internal/apm/settings/custom_links\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4176,7 +4176,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/settings/custom_links\", ", + "<\"POST /internal/apm/settings/custom_links\", ", "TypeC", "<{ body: ", "IntersectionC", @@ -4220,7 +4220,7 @@ }, ", void, ", "APMRouteCreateOptions", - ">; } & { \"PUT /api/apm/settings/custom_links/{id}\": ", + ">; } & { \"PUT /internal/apm/settings/custom_links/{id}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4228,7 +4228,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"PUT /api/apm/settings/custom_links/{id}\", ", + "<\"PUT /internal/apm/settings/custom_links/{id}\", ", "TypeC", "<{ path: ", "TypeC", @@ -4276,7 +4276,7 @@ }, ", void, ", "APMRouteCreateOptions", - ">; } & { \"DELETE /api/apm/settings/custom_links/{id}\": ", + ">; } & { \"DELETE /internal/apm/settings/custom_links/{id}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4284,7 +4284,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"DELETE /api/apm/settings/custom_links/{id}\", ", + "<\"DELETE /internal/apm/settings/custom_links/{id}\", ", "TypeC", "<{ path: ", "TypeC", @@ -4382,7 +4382,7 @@ }, ", void, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/fleet/has_data\": ", + ">; } & { \"GET /internal/apm/fleet/has_data\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4390,7 +4390,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/fleet/has_data\", undefined, ", + "<\"GET /internal/apm/fleet/has_data\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4400,7 +4400,7 @@ }, ", { hasData: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/fleet/agents\": ", + ">; } & { \"GET /internal/apm/fleet/agents\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4408,7 +4408,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/fleet/agents\", undefined, ", + "<\"GET /internal/apm/fleet/agents\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4418,7 +4418,7 @@ }, ", { cloudStandaloneSetup: { apmServerUrl: string | undefined; secretToken: string | undefined; } | undefined; isFleetEnabled: boolean; fleetAgents: { id: string; name: string; apmServerUrl: any; secretToken: any; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"POST /api/apm/fleet/apm_server_schema\": ", + ">; } & { \"POST /internal/apm/fleet/apm_server_schema\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4426,7 +4426,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/fleet/apm_server_schema\", ", + "<\"POST /internal/apm/fleet/apm_server_schema\", ", "TypeC", "<{ body: ", "TypeC", @@ -4446,7 +4446,7 @@ }, ", void, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/fleet/apm_server_schema/unsupported\": ", + ">; } & { \"GET /internal/apm/fleet/apm_server_schema/unsupported\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4454,7 +4454,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/fleet/apm_server_schema/unsupported\", undefined, ", + "<\"GET /internal/apm/fleet/apm_server_schema/unsupported\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4464,7 +4464,7 @@ }, ", { unsupported: { key: string; value: any; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/fleet/migration_check\": ", + ">; } & { \"GET /internal/apm/fleet/migration_check\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4472,7 +4472,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/fleet/migration_check\", undefined, ", + "<\"GET /internal/apm/fleet/migration_check\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4482,7 +4482,7 @@ }, ", { has_cloud_agent_policy: boolean; has_cloud_apm_package_policy: boolean; cloud_apm_migration_enabled: boolean; has_required_role: boolean | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"POST /api/apm/fleet/cloud_apm_package_policy\": ", + ">; } & { \"POST /internal/apm/fleet/cloud_apm_package_policy\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4490,7 +4490,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/apm/fleet/cloud_apm_package_policy\", undefined, ", + "<\"POST /internal/apm/fleet/cloud_apm_package_policy\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4508,7 +4508,7 @@ }, "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/top_backends\": ", + ">; } & { \"GET /internal/apm/backends/top_backends\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4516,7 +4516,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/top_backends\", ", + "<\"GET /internal/apm/backends/top_backends\", ", "IntersectionC", "<[", "TypeC", @@ -4584,7 +4584,7 @@ "Node", "; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/{backendName}/upstream_services\": ", + ">; } & { \"GET /internal/apm/backends/{backendName}/upstream_services\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4592,7 +4592,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/{backendName}/upstream_services\", ", + "<\"GET /internal/apm/backends/{backendName}/upstream_services\", ", "IntersectionC", "<[", "TypeC", @@ -4666,7 +4666,7 @@ "Node", "; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/{backendName}/metadata\": ", + ">; } & { \"GET /internal/apm/backends/{backendName}/metadata\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4674,7 +4674,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/{backendName}/metadata\", ", + "<\"GET /internal/apm/backends/{backendName}/metadata\", ", "TypeC", "<{ path: ", "TypeC", @@ -4696,7 +4696,7 @@ }, ", { metadata: { spanType: string | undefined; spanSubtype: string | undefined; }; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/{backendName}/charts/latency\": ", + ">; } & { \"GET /internal/apm/backends/{backendName}/charts/latency\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4704,7 +4704,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/{backendName}/charts/latency\", ", + "<\"GET /internal/apm/backends/{backendName}/charts/latency\", ", "TypeC", "<{ path: ", "TypeC", @@ -4750,7 +4750,7 @@ }, ", { currentTimeseries: { x: number; y: number; }[]; comparisonTimeseries: { x: number; y: number; }[] | null; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/{backendName}/charts/throughput\": ", + ">; } & { \"GET /internal/apm/backends/{backendName}/charts/throughput\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4758,7 +4758,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/{backendName}/charts/throughput\", ", + "<\"GET /internal/apm/backends/{backendName}/charts/throughput\", ", "TypeC", "<{ path: ", "TypeC", @@ -4804,7 +4804,7 @@ }, ", { currentTimeseries: { x: number; y: number | null; }[]; comparisonTimeseries: { x: number; y: number | null; }[] | null; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/backends/{backendName}/charts/error_rate\": ", + ">; } & { \"GET /internal/apm/backends/{backendName}/charts/error_rate\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4812,7 +4812,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/backends/{backendName}/charts/error_rate\", ", + "<\"GET /internal/apm/backends/{backendName}/charts/error_rate\", ", "TypeC", "<{ path: ", "TypeC", @@ -4858,7 +4858,7 @@ }, ", { currentTimeseries: { x: number; y: number; }[]; comparisonTimeseries: { x: number; y: number; }[] | null; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/fallback_to_transactions\": ", + ">; } & { \"GET /internal/apm/fallback_to_transactions\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4866,7 +4866,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/fallback_to_transactions\", ", + "<\"GET /internal/apm/fallback_to_transactions\", ", "PartialC", "<{ query: ", "IntersectionC", @@ -4890,7 +4890,7 @@ }, ", { fallbackToTransactions: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/has_data\": ", + ">; } & { \"GET /internal/apm/has_data\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4898,7 +4898,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/has_data\", undefined, ", + "<\"GET /internal/apm/has_data\", undefined, ", { "pluginId": "apm", "scope": "server", @@ -4908,7 +4908,7 @@ }, ", { hasData: boolean; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/event_metadata/{processorEvent}/{id}\": ", + ">; } & { \"GET /internal/apm/event_metadata/{processorEvent}/{id}\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -4916,7 +4916,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/event_metadata/{processorEvent}/{id}\", ", + "<\"GET /internal/apm/event_metadata/{processorEvent}/{id}\", ", "TypeC", "<{ path: ", "TypeC", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index a3fb1df512fa5..d9e53e6ec9df8 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -10,7 +10,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex --- import apmObj from './apm.json'; - +The user interface for Elastic APM Contact [APM UI](https://github.com/orgs/elastic/teams/apm-ui) for questions regarding this plugin. diff --git a/api_docs/charts.json b/api_docs/charts.json index 9f6d07287eba1..5d4f047a247e2 100644 --- a/api_docs/charts.json +++ b/api_docs/charts.json @@ -975,9 +975,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" } ], @@ -1004,7 +1004,7 @@ "tags": [], "label": "ColorSchemaParams", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false, "children": [ { @@ -1017,13 +1017,13 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" } ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1033,7 +1033,7 @@ "tags": [], "label": "invertColors", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false } ], @@ -1255,7 +1255,7 @@ "tags": [], "label": "Labels", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false, "children": [ { @@ -1268,7 +1268,7 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1281,7 +1281,7 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1294,7 +1294,7 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1307,7 +1307,7 @@ "signature": [ "number | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1320,7 +1320,7 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1333,7 +1333,7 @@ "signature": [ "number | null | undefined" ], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false } ], @@ -1830,9 +1830,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" } ], @@ -1923,7 +1923,7 @@ "tags": [], "label": "Style", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false, "children": [ { @@ -1933,7 +1933,7 @@ "tags": [], "label": "bgFill", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1943,7 +1943,7 @@ "tags": [], "label": "bgColor", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1953,7 +1953,7 @@ "tags": [], "label": "labelColor", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1963,7 +1963,7 @@ "tags": [], "label": "subText", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false }, { @@ -1973,7 +1973,7 @@ "tags": [], "label": "fontSize", "description": [], - "path": "src/plugins/charts/public/static/components/types.ts", + "path": "src/plugins/charts/common/types.ts", "deprecated": false } ], @@ -2041,9 +2041,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchema", + "section": "def-common.ColorSchema", "text": "ColorSchema" }, "[]" @@ -2117,9 +2117,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchema", + "section": "def-common.ColorSchema", "text": "ColorSchema" }, "[]" @@ -2202,9 +2202,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".Blues" @@ -2257,9 +2257,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".Greens" @@ -2312,9 +2312,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".Greys" @@ -2367,9 +2367,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".Reds" @@ -2422,9 +2422,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".YellowToRed" @@ -2477,9 +2477,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemas", + "section": "def-common.ColorSchemas", "text": "ColorSchemas" }, ".GreenToRed" @@ -2946,6 +2946,51 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "charts", + "id": "def-common.getHeatmapColors", + "type": "Function", + "tags": [], + "label": "getHeatmapColors", + "description": [], + "signature": [ + "(value: any, colorSchemaName: string) => string" + ], + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.getHeatmapColors.$1", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "charts", + "id": "def-common.getHeatmapColors.$2", + "type": "string", + "tags": [], + "label": "colorSchemaName", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "charts", "id": "def-common.palette", @@ -3084,6 +3129,116 @@ } ], "interfaces": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorMap", + "type": "Interface", + "tags": [], + "label": "ColorMap", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorMap.Unnamed", + "type": "Any", + "tags": [], + "label": "Unnamed", + "description": [], + "signature": [ + "any" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.ColorSchema", + "type": "Interface", + "tags": [], + "label": "ColorSchema", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorSchema.value", + "type": "Enum", + "tags": [], + "label": "value", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + } + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.ColorSchema.text", + "type": "string", + "tags": [], + "label": "text", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.ColorSchemaParams", + "type": "Interface", + "tags": [], + "label": "ColorSchemaParams", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorSchemaParams.colorSchema", + "type": "Enum", + "tags": [], + "label": "colorSchema", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + } + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.ColorSchemaParams.invertColors", + "type": "boolean", + "tags": [], + "label": "invertColors", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "charts", "id": "def-common.CustomPaletteArguments", @@ -3293,6 +3448,97 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "charts", + "id": "def-common.Labels", + "type": "Interface", + "tags": [], + "label": "Labels", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.Labels.color", + "type": "string", + "tags": [], + "label": "color", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Labels.filter", + "type": "CompoundType", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Labels.overwriteColor", + "type": "CompoundType", + "tags": [], + "label": "overwriteColor", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Labels.rotate", + "type": "number", + "tags": [], + "label": "rotate", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Labels.show", + "type": "CompoundType", + "tags": [], + "label": "show", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Labels.truncate", + "type": "CompoundType", + "tags": [], + "label": "truncate", + "description": [], + "signature": [ + "number | null | undefined" + ], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "charts", "id": "def-common.PaletteOutput", @@ -3354,29 +3600,159 @@ }, { "parentPluginId": "charts", - "id": "def-common.SystemPaletteArguments", + "id": "def-common.RawColorSchema", "type": "Interface", "tags": [], - "label": "SystemPaletteArguments", + "label": "RawColorSchema", "description": [], - "path": "src/plugins/charts/common/palette.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { "parentPluginId": "charts", - "id": "def-common.SystemPaletteArguments.name", - "type": "string", + "id": "def-common.RawColorSchema.id", + "type": "Enum", "tags": [], - "label": "name", + "label": "id", "description": [], - "path": "src/plugins/charts/common/palette.ts", + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + } + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false - } - ], - "initialIsOpen": false - } + }, + { + "parentPluginId": "charts", + "id": "def-common.RawColorSchema.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.RawColorSchema.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Style", + "type": "Interface", + "tags": [], + "label": "Style", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.Style.bgFill", + "type": "string", + "tags": [], + "label": "bgFill", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Style.bgColor", + "type": "boolean", + "tags": [], + "label": "bgColor", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Style.labelColor", + "type": "boolean", + "tags": [], + "label": "labelColor", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Style.subText", + "type": "string", + "tags": [], + "label": "subText", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.Style.fontSize", + "type": "number", + "tags": [], + "label": "fontSize", + "description": [], + "path": "src/plugins/charts/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.SystemPaletteArguments", + "type": "Interface", + "tags": [], + "label": "SystemPaletteArguments", + "description": [], + "path": "src/plugins/charts/common/palette.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.SystemPaletteArguments.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "src/plugins/charts/common/palette.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ], + "enums": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorSchemas", + "type": "Enum", + "tags": [], + "label": "ColorSchemas", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "initialIsOpen": false + } ], - "enums": [], "misc": [ { "parentPluginId": "charts", @@ -3392,6 +3768,52 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "charts", + "id": "def-common.ColorMode", + "type": "Type", + "tags": [], + "label": "ColorMode", + "description": [], + "signature": [ + "\"Background\" | \"Labels\" | \"None\"" + ], + "path": "src/plugins/charts/common/static/components/collections.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.colorSchemas", + "type": "Array", + "tags": [], + "label": "colorSchemas", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchema", + "text": "ColorSchema" + }, + "[]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.defaultCountLabel", + "type": "string", + "tags": [], + "label": "defaultCountLabel", + "description": [], + "path": "src/plugins/charts/common/static/components/collections.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "charts", "id": "def-common.defaultCustomColors", @@ -3406,6 +3828,20 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "charts", + "id": "def-common.LabelRotation", + "type": "Type", + "tags": [], + "label": "LabelRotation", + "description": [], + "signature": [ + "number" + ], + "path": "src/plugins/charts/common/static/components/collections.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "charts", "id": "def-common.paletteIds", @@ -3419,8 +3855,415 @@ "path": "src/plugins/charts/common/constants.ts", "deprecated": false, "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.truncatedColorSchemas", + "type": "Array", + "tags": [], + "label": "truncatedColorSchemas", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchema", + "text": "ColorSchema" + }, + "[]" + ], + "path": "src/plugins/charts/common/static/color_maps/truncated_color_maps.ts", + "deprecated": false, + "initialIsOpen": false } ], - "objects": [] + "objects": [ + { + "parentPluginId": "charts", + "id": "def-common.ColorMode", + "type": "Object", + "tags": [], + "label": "ColorMode", + "description": [], + "signature": [ + "{ readonly Background: \"Background\"; readonly Labels: \"Labels\"; readonly None: \"None\"; }" + ], + "path": "src/plugins/charts/common/static/components/collections.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.LabelRotation", + "type": "Object", + "tags": [], + "label": "LabelRotation", + "description": [], + "signature": [ + "{ readonly Horizontal: number; readonly Vertical: number; readonly Angled: number; }" + ], + "path": "src/plugins/charts/common/static/components/collections.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.truncatedColorMaps", + "type": "Object", + "tags": [], + "label": "truncatedColorMaps", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/truncated_color_maps.ts", + "deprecated": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps", + "type": "Object", + "tags": [], + "label": "vislibColorMaps", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Blues", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.Blues]", + "description": [ + "// Sequential" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Blues.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".Blues" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Blues.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Blues.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greens", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.Greens]", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greens.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".Greens" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greens.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greens.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greys", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.Greys]", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greys.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".Greys" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greys.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Greys.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Reds", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.Reds]", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Reds.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".Reds" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Reds.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.Reds.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.YellowToRed", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.YellowToRed]", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.YellowToRed.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".YellowToRed" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.YellowToRed.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.YellowToRed.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.GreenToRed", + "type": "Object", + "tags": [], + "label": "[ColorSchemas.GreenToRed]", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.GreenToRed.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + }, + ".GreenToRed" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.GreenToRed.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + }, + { + "parentPluginId": "charts", + "id": "def-common.vislibColorMaps.ColorSchemas.GreenToRed.value", + "type": "Array", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "[number, number[]][]" + ], + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", + "deprecated": false + } + ] + } + ], + "initialIsOpen": false + } + ] } } \ No newline at end of file diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index c8159a3bc0dfa..8d31f6ad1d640 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -18,7 +18,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 223 | 2 | 192 | 3 | +| 285 | 4 | 253 | 3 | ## Client @@ -53,12 +53,18 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) ## Common +### Objects + + ### Functions ### Interfaces +### Enums + + ### Consts, variables and types diff --git a/api_docs/core.json b/api_docs/core.json index 8b64ef86dbf16..c288037b4486d 100644 --- a/api_docs/core.json +++ b/api_docs/core.json @@ -1603,7 +1603,7 @@ "label": "links", "description": [], "signature": [ - "{ readonly settings: string; readonly apm: { readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; }; readonly canvas: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; readonly suricataModule: string; readonly zeekModule: string; }; readonly auditbeat: { readonly base: string; readonly auditdModule: string; readonly systemModule: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly libbeat: { readonly getStarted: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; readonly sessionLimits: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly rollupJobs: string; readonly elasticsearch: Record; readonly siem: { readonly privileges: string; readonly guide: string; readonly gettingStarted: string; readonly ml: string; readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; readonly autocompleteChanges: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Readonly<{ guide: string; infrastructureThreshold: string; logsThreshold: string; metricsThreshold: string; monitorStatus: string; monitorUptime: string; tlsCertificate: string; uptimeDurationAnomaly: string; }>; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; readonly fleet: Readonly<{ guide: string; fleetServer: string; fleetServerAddFleetServer: string; settings: string; settingsFleetServerHostSettings: string; troubleshooting: string; elasticAgent: string; datastreams: string; datastreamsNamingScheme: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; }>; readonly ecs: { readonly guide: string; }; }" + "{ readonly settings: string; readonly apm: { readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; }; readonly canvas: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; readonly suricataModule: string; readonly zeekModule: string; }; readonly auditbeat: { readonly base: string; readonly auditdModule: string; readonly systemModule: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly libbeat: { readonly getStarted: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; readonly sessionLimits: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly rollupJobs: string; readonly elasticsearch: Record; readonly siem: { readonly privileges: string; readonly guide: string; readonly gettingStarted: string; readonly ml: string; readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; readonly troubleshootGaps: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; readonly autocompleteChanges: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Readonly<{ guide: string; infrastructureThreshold: string; logsThreshold: string; metricsThreshold: string; monitorStatus: string; monitorUptime: string; tlsCertificate: string; uptimeDurationAnomaly: string; }>; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly spaces: Readonly<{ kibanaLegacyUrlAliases: string; kibanaDisableLegacyUrlAliasesApi: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; readonly fleet: Readonly<{ guide: string; fleetServer: string; fleetServerAddFleetServer: string; settings: string; settingsFleetServerHostSettings: string; troubleshooting: string; elasticAgent: string; datastreams: string; datastreamsNamingScheme: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; learnMoreBlog: string; }>; readonly ecs: { readonly guide: string; }; readonly clients: { readonly guide: string; readonly goOverview: string; readonly javaIndex: string; readonly jsIntro: string; readonly netGuide: string; readonly perlGuide: string; readonly phpGuide: string; readonly pythonGuide: string; readonly rubyOverview: string; readonly rustGuide: string; }; }" ], "path": "src/core/public/doc_links/doc_links_service.ts", "deprecated": false @@ -1611,40 +1611,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "core", - "id": "def-public.DomainDeprecationDetails", - "type": "Interface", - "tags": [], - "label": "DomainDeprecationDetails", - "description": [], - "signature": [ - "DomainDeprecationDetails", - " extends ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.DeprecationsDetails", - "text": "DeprecationsDetails" - } - ], - "path": "src/core/server/deprecations/types.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-public.DomainDeprecationDetails.domainId", - "type": "string", - "tags": [], - "label": "domainId", - "description": [], - "path": "src/core/server/deprecations/types.ts", - "deprecated": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "core", "id": "def-public.EnvironmentMode", @@ -8281,6 +8247,45 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecationContext", + "type": "Interface", + "tags": [], + "label": "ConfigDeprecationContext", + "description": [ + "\nDeprecation context provided to {@link ConfigDeprecation | config deprecations}\n" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecationContext.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "The current Kibana version, e.g `7.16.1`, `8.0.0`" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecationContext.branch", + "type": "string", + "tags": [], + "label": "branch", + "description": [ + "The current Kibana branch, e.g `7.x`, `7.16`, `master`" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "core", "id": "def-server.ConfigDeprecationFactory", @@ -8306,7 +8311,13 @@ "(deprecatedKey: string, removeBy: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -8371,7 +8382,13 @@ "(deprecatedKey: string, removeBy: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -8436,7 +8453,13 @@ "(oldKey: string, newKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -8501,7 +8524,13 @@ "(oldKey: string, newKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -8566,7 +8595,13 @@ "(unusedKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -8617,7 +8652,13 @@ "(unusedKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", "deprecated": false, @@ -9552,7 +9593,9 @@ "type": "string", "tags": [], "label": "documentationUrl", - "description": [], + "description": [ + "(optional) link to the documentation for more details on the deprecation." + ], "signature": [ "string | undefined" ], @@ -9565,7 +9608,9 @@ "type": "CompoundType", "tags": [], "label": "requireRestart", - "description": [], + "description": [ + "(optional) specify the fix for this deprecation requires a full kibana restart." + ], "signature": [ "boolean | undefined" ], @@ -9578,7 +9623,9 @@ "type": "Object", "tags": [], "label": "correctiveActions", - "description": [], + "description": [ + "corrective action needed to fix this deprecation." + ], "signature": [ "{ api?: { path: string; method: \"PUT\" | \"POST\"; body?: { [key: string]: any; } | undefined; } | undefined; manualSteps: string[]; }" ], @@ -16830,6 +16877,123 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation", + "type": "Type", + "tags": [], + "label": "ConfigDeprecation", + "description": [ + "\nConfiguration deprecation returned from {@link ConfigDeprecationProvider} that handles a single deprecation from the configuration.\n" + ], + "signature": [ + "(config: Readonly<{ [x: string]: any; }>, fromPath: string, addDeprecation: ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.AddConfigDeprecation", + "text": "AddConfigDeprecation" + }, + ", context: ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationContext", + "text": "ConfigDeprecationContext" + }, + ") => void | ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationCommand", + "text": "ConfigDeprecationCommand" + } + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [ + "must not be mutated, return {@link ConfigDeprecationCommand} to change config shape." + ], + "signature": [ + "{ readonly [x: string]: any; }" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation.$2", + "type": "string", + "tags": [], + "label": "fromPath", + "description": [], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation.$3", + "type": "Function", + "tags": [], + "label": "addDeprecation", + "description": [], + "signature": [ + "(details: ", + "DeprecatedConfigDetails", + ") => void" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation.$3.$1", + "type": "Object", + "tags": [], + "label": "details", + "description": [], + "signature": [ + "DeprecatedConfigDetails" + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "core", + "id": "def-server.ConfigDeprecation.$4", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationContext", + "text": "ConfigDeprecationContext" + } + ], + "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "core", "id": "def-server.ConfigDeprecationProvider", @@ -16849,7 +17013,13 @@ "text": "ConfigDeprecationFactory" }, ") => ", - "ConfigDeprecation", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + }, "[]" ], "path": "node_modules/@kbn/config/target_types/deprecation/types.d.ts", @@ -17974,7 +18144,7 @@ "EcsHttp", " | undefined; log?: Pick<", "EcsLog", - ", \"origin\" | \"original\" | \"file\" | \"syslog\"> | undefined; network?: ", + ", \"origin\" | \"file\" | \"syslog\"> | undefined; network?: ", "EcsNetwork", " | undefined; observer?: ", "EcsObserver", diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 856db3cf8871b..018a9f1beda6c 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2293 | 27 | 1020 | 29 | +| 2300 | 27 | 1019 | 29 | ## Client diff --git a/api_docs/core_application.json b/api_docs/core_application.json index 71e4244af778b..52f50c364fdba 100644 --- a/api_docs/core_application.json +++ b/api_docs/core_application.json @@ -1664,7 +1664,7 @@ "tags": [], "label": "euiIconType", "description": [ - "\nA EUI iconType that will be used for the app's icon. This icon\ntakes precendence over the `icon` property." + "\nA EUI iconType that will be used for the app's icon. This icon\ntakes precedence over the `icon` property." ], "signature": [ "string | undefined" diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index bf9e610a24b78..1c01073421f69 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2293 | 27 | 1020 | 29 | +| 2300 | 27 | 1019 | 29 | ## Client diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index c217d2ae66f73..18244445385ca 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2293 | 27 | 1020 | 29 | +| 2300 | 27 | 1019 | 29 | ## Client diff --git a/api_docs/core_http.json b/api_docs/core_http.json index f6345d6f6e933..94ee961f265b7 100644 --- a/api_docs/core_http.json +++ b/api_docs/core_http.json @@ -1249,7 +1249,7 @@ "tags": [], "label": "fetch", "description": [ - "Makes an HTTP request. Defaults to a GET request unless overriden. See {@link HttpHandler} for options." + "Makes an HTTP request. Defaults to a GET request unless overridden. See {@link HttpHandler} for options." ], "signature": [ { diff --git a/api_docs/core_http.mdx b/api_docs/core_http.mdx index 739916c56ecfc..ae5747c711b97 100644 --- a/api_docs/core_http.mdx +++ b/api_docs/core_http.mdx @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2293 | 27 | 1020 | 29 | +| 2300 | 27 | 1019 | 29 | ## Client diff --git a/api_docs/core_saved_objects.json b/api_docs/core_saved_objects.json index f5b601e346dec..91af1d2465c3d 100644 --- a/api_docs/core_saved_objects.json +++ b/api_docs/core_saved_objects.json @@ -5600,7 +5600,7 @@ "tags": [], "label": "objectTransformError", "description": [ - "\nError returned when a {@link SavedObjectsExportTransform | export tranform} threw an error" + "\nError returned when a {@link SavedObjectsExportTransform | export transform} threw an error" ], "signature": [ "(objects: ", @@ -5656,7 +5656,7 @@ "tags": [], "label": "invalidTransformError", "description": [ - "\nError returned when a {@link SavedObjectsExportTransform | export tranform} performed an invalid operation\nduring the transform, such as removing objects from the export, or changing an object's type or id." + "\nError returned when a {@link SavedObjectsExportTransform | export transform} performed an invalid operation\nduring the transform, such as removing objects from the export, or changing an object's type or id." ], "signature": [ "(objectKeys: string[]) => ", @@ -6599,7 +6599,7 @@ ], "label": "resolveImportErrors", "description": [ - "\nResolve and return saved object import errors.\nSee the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed informations.\n" + "\nResolve and return saved object import errors.\nSee the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed information.\n" ], "signature": [ "({ readStream, createNewCopies, namespace, retries, }: ", @@ -16148,7 +16148,7 @@ "tags": [], "label": "SavedObjectsClientContract", "description": [ - "\nSaved Objects is Kibana's data persisentence mechanism allowing plugins to\nuse Elasticsearch for storing plugin state.\n\n## SavedObjectsClient errors\n\nSince the SavedObjectsClient has its hands in everything we\nare a little paranoid about the way we present errors back to\nto application code. Ideally, all errors will be either:\n\n 1. Caused by bad implementation (ie. undefined is not a function) and\n as such unpredictable\n 2. An error that has been classified and decorated appropriately\n by the decorators in {@link SavedObjectsErrorHelpers}\n\nType 1 errors are inevitable, but since all expected/handle-able errors\nshould be Type 2 the `isXYZError()` helpers exposed at\n`SavedObjectsErrorHelpers` should be used to understand and manage error\nresponses from the `SavedObjectsClient`.\n\nType 2 errors are decorated versions of the source error, so if\nthe elasticsearch client threw an error it will be decorated based\non its type. That means that rather than looking for `error.body.error.type` or\ndoing substring checks on `error.body.error.reason`, just use the helpers to\nunderstand the meaning of the error:\n\n ```js\n if (SavedObjectsErrorHelpers.isNotFoundError(error)) {\n // handle 404\n }\n\n if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) {\n // 401 handling should be automatic, but in case you wanted to know\n }\n\n // always rethrow the error unless you handle it\n throw error;\n ```\n\n### 404s from missing index\n\nFrom the perspective of application code and APIs the SavedObjectsClient is\na black box that persists objects. One of the internal details that users have\nno control over is that we use an elasticsearch index for persistance and that\nindex might be missing.\n\nAt the time of writing we are in the process of transitioning away from the\noperating assumption that the SavedObjects index is always available. Part of\nthis transition is handling errors resulting from an index missing. These used\nto trigger a 500 error in most cases, and in others cause 404s with different\nerror messages.\n\nFrom my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The\nobject the request/call was targeting could not be found. This is why #14141\ntakes special care to ensure that 404 errors are generic and don't distinguish\nbetween index missing or document missing.\n\nSee {@link SavedObjectsClient}\nSee {@link SavedObjectsErrorHelpers}\n" + "\nSaved Objects is Kibana's data persisentence mechanism allowing plugins to\nuse Elasticsearch for storing plugin state.\n\n## SavedObjectsClient errors\n\nSince the SavedObjectsClient has its hands in everything we\nare a little paranoid about the way we present errors back to\nto application code. Ideally, all errors will be either:\n\n 1. Caused by bad implementation (ie. undefined is not a function) and\n as such unpredictable\n 2. An error that has been classified and decorated appropriately\n by the decorators in {@link SavedObjectsErrorHelpers}\n\nType 1 errors are inevitable, but since all expected/handle-able errors\nshould be Type 2 the `isXYZError()` helpers exposed at\n`SavedObjectsErrorHelpers` should be used to understand and manage error\nresponses from the `SavedObjectsClient`.\n\nType 2 errors are decorated versions of the source error, so if\nthe elasticsearch client threw an error it will be decorated based\non its type. That means that rather than looking for `error.body.error.type` or\ndoing substring checks on `error.body.error.reason`, just use the helpers to\nunderstand the meaning of the error:\n\n ```js\n if (SavedObjectsErrorHelpers.isNotFoundError(error)) {\n // handle 404\n }\n\n if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) {\n // 401 handling should be automatic, but in case you wanted to know\n }\n\n // always rethrow the error unless you handle it\n throw error;\n ```\n\n### 404s from missing index\n\nFrom the perspective of application code and APIs the SavedObjectsClient is\na black box that persists objects. One of the internal details that users have\nno control over is that we use an elasticsearch index for persistence and that\nindex might be missing.\n\nAt the time of writing we are in the process of transitioning away from the\noperating assumption that the SavedObjects index is always available. Part of\nthis transition is handling errors resulting from an index missing. These used\nto trigger a 500 error in most cases, and in others cause 404s with different\nerror messages.\n\nFrom my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The\nobject the request/call was targeting could not be found. This is why #14141\ntakes special care to ensure that 404 errors are generic and don't distinguish\nbetween index missing or document missing.\n\nSee {@link SavedObjectsClient}\nSee {@link SavedObjectsErrorHelpers}\n" ], "signature": [ "{ get: (type: string, id: string, options?: ", diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index 66d66b3d41c18..5fc7bc63466b1 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2293 | 27 | 1020 | 29 | +| 2300 | 27 | 1019 | 29 | ## Client diff --git a/api_docs/dashboard.json b/api_docs/dashboard.json index f43e6e3923ca9..b42846c747bfa 100644 --- a/api_docs/dashboard.json +++ b/api_docs/dashboard.json @@ -2426,15 +2426,15 @@ "references": [ { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx" + "path": "x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts" + "path": "x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx" + "path": "x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx" } ] }, diff --git a/api_docs/dashboard_enhanced.json b/api_docs/dashboard_enhanced.json index 9712b25f7377a..92bdfbc11b3f6 100644 --- a/api_docs/dashboard_enhanced.json +++ b/api_docs/dashboard_enhanced.json @@ -617,7 +617,15 @@ "section": "def-server.SerializableRecord", "text": "SerializableRecord" }, - ">): void; }" + ">): void; setAnonymousAccessServiceProvider: (provider: () => ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.AnonymousAccessServiceContract", + "text": "AnonymousAccessServiceContract" + }, + ") => void; }" ], "path": "x-pack/plugins/dashboard_enhanced/public/plugin.ts", "deprecated": false diff --git a/api_docs/data.json b/api_docs/data.json index 31d0a919b2d44..ab02b81539cf2 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -4170,35 +4170,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", @@ -12311,10 +12311,6 @@ "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/utils.ts" }, - { - "plugin": "dataViews", - "path": "src/plugins/data_views/common/fields/utils.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/data_view_field.ts" @@ -13309,14 +13305,6 @@ "plugin": "monitoring", "path": "x-pack/plugins/monitoring/public/lib/kuery.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts" @@ -13529,14 +13517,6 @@ "plugin": "timelines", "path": "x-pack/plugins/timelines/public/mock/index_pattern.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, { "plugin": "infra", "path": "x-pack/plugins/infra/target/types/public/containers/with_kuery_autocompletion.d.ts" @@ -13801,6 +13781,14 @@ "plugin": "infra", "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts" @@ -15902,7 +15890,7 @@ "section": "def-common.FilterMeta", "text": "FilterMeta" }, - "; exists?: { field: string; } | undefined; }" + "; query: { exists?: { field: string; } | undefined; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, @@ -18097,6 +18085,11 @@ ], "label": "IFieldSubType", "description": [], + "signature": [ + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional" + ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, "removeBy": "8.1", @@ -19798,9 +19791,9 @@ }, " & { meta: ", "MatchAllFilterMeta", - "; match_all: ", + "; query: { match_all: ", "QueryDslMatchAllQuery", - "; }" + "; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, @@ -19929,7 +19922,7 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; range: { [key: string]: ", + "; query: { range: { [key: string]: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -19937,7 +19930,7 @@ "section": "def-common.RangeFilterParams", "text": "RangeFilterParams" }, - "; }; }" + "; }; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, @@ -20319,35 +20312,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts" }, { "plugin": "maps", @@ -20489,10 +20482,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx" @@ -21515,66 +21504,6 @@ } ] }, - { - "parentPluginId": "data", - "id": "def-public.esFilters.isMissingFilter", - "type": "Function", - "tags": [], - "label": "isMissingFilter", - "description": [], - "signature": [ - "(filter: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - ") => filter is ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.MissingFilter", - "text": "MissingFilter" - } - ], - "path": "src/plugins/data/public/deprecated.ts", - "deprecated": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "data", - "id": "def-public.esFilters.isMissingFilter.$1", - "type": "Object", - "tags": [], - "label": "filter", - "description": [], - "signature": [ - "{ $state?: { store: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterStateStore", - "text": "FilterStateStore" - }, - "; } | undefined; meta: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterMeta", - "text": "FilterMeta" - }, - "; query?: Record | undefined; }" - ], - "path": "node_modules/@kbn/es-query/target_types/filters/build_filters/missing_filter.d.ts", - "deprecated": false - } - ] - }, { "parentPluginId": "data", "id": "def-public.esFilters.isQueryStringFilter", @@ -22563,7 +22492,7 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; range: { [key: string]: ", + "; query: { range: { [key: string]: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -22571,7 +22500,7 @@ "section": "def-common.RangeFilterParams", "text": "RangeFilterParams" }, - "; }; }" + "; }; }; }" ], "path": "src/plugins/data/public/query/timefilter/lib/change_time_filter.ts", "deprecated": false @@ -22630,7 +22559,7 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; range: { [key: string]: ", + "; query: { range: { [key: string]: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -22638,7 +22567,7 @@ "section": "def-common.RangeFilterParams", "text": "RangeFilterParams" }, - "; }; }" + "; }; }; }" ], "path": "src/plugins/data/public/query/timefilter/lib/change_time_filter.ts", "deprecated": false @@ -24148,15 +24077,15 @@ "label": "isNestedField", "description": [], "signature": [ - "(field: ", + "(field: Pick<", { - "pluginId": "dataViews", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" }, - ") => boolean" + ", \"subType\">) => boolean" ], "path": "src/plugins/data/public/index.ts", "deprecated": false, @@ -24170,13 +24099,150 @@ "label": "field", "description": [], "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" - } + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.isMultiField", + "type": "Function", + "tags": [], + "label": "isMultiField", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => boolean" + ], + "path": "src/plugins/data/public/index.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.isMultiField.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.getFieldSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeMulti", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "src/plugins/data/public/index.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.getFieldSubtypeMulti.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.getFieldSubtypeNested", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeNested", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "src/plugins/data/public/index.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-public.indexPatterns.getFieldSubtypeNested.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" ], "path": "src/plugins/data_views/common/fields/utils.ts", "deprecated": false @@ -26318,10 +26384,6 @@ "plugin": "indexPatternManagement", "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx" }, - { - "plugin": "visTypeMetric", - "path": "src/plugins/vis_types/metric/public/plugin.ts" - }, { "plugin": "visTypePie", "path": "src/plugins/vis_types/pie/public/pie_component.tsx" @@ -29774,35 +29836,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", @@ -33985,10 +34047,6 @@ "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/utils.ts" }, - { - "plugin": "dataViews", - "path": "src/plugins/data_views/common/fields/utils.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/data_view_field.ts" @@ -36961,6 +37019,11 @@ ], "label": "IFieldSubType", "description": [], + "signature": [ + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional" + ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, "removeBy": "8.1", @@ -41065,18 +41128,14 @@ { "parentPluginId": "data", "id": "def-common.DataViewField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "src/plugins/data_views/common/fields/data_view_field.ts", @@ -41127,6 +41186,82 @@ "path": "src/plugins/data_views/common/fields/data_view_field.ts", "deprecated": false }, + { + "parentPluginId": "data", + "id": "def-common.DataViewField.isSubtypeNested", + "type": "Function", + "tags": [], + "label": "isSubtypeNested", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "data", + "id": "def-common.DataViewField.isSubtypeMulti", + "type": "Function", + "tags": [], + "label": "isSubtypeMulti", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "data", + "id": "def-common.DataViewField.getSubtypeNested", + "type": "Function", + "tags": [], + "label": "getSubtypeNested", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "data", + "id": "def-common.DataViewField.getSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getSubtypeMulti", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-common.DataViewField.deleteCount", @@ -41151,13 +41286,9 @@ "description": [], "signature": [ "() => { count: number; script: string | undefined; lang: \"painless\" | \"expression\" | \"mustache\" | \"java\" | undefined; conflictDescriptions: Record | undefined; name: string; type: string; esTypes: string[] | undefined; scripted: boolean; searchable: boolean; aggregatable: boolean; readFromDocValues: boolean; subType: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; customLabel: string | undefined; }" ], "path": "src/plugins/data_views/common/fields/data_view_field.ts", @@ -43916,35 +44047,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", @@ -49135,6 +49266,106 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.getFieldSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeMulti", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-common.getFieldSubtypeMulti.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "data", + "id": "def-common.getFieldSubtypeNested", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeNested", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-common.getFieldSubtypeNested.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.getFilterableKbnTypeNames", @@ -49764,64 +49995,41 @@ }, { "parentPluginId": "data", - "id": "def-common.isMissingFilter", + "id": "def-common.isMultiField", "type": "Function", - "tags": [ - "deprecated" - ], - "label": "isMissingFilter", + "tags": [], + "label": "isMultiField", "description": [], "signature": [ - "(filter: ", + "(field: Pick<", { "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" }, - ") => filter is ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.MissingFilter", - "text": "MissingFilter" - } + ", \"subType\">) => boolean" ], - "path": "src/plugins/data/common/es_query/index.ts", - "deprecated": true, - "removeBy": "8.1", - "references": [], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, "returnComment": [], "children": [ { "parentPluginId": "data", - "id": "def-common.isMissingFilter.$1", + "id": "def-common.isMultiField.$1", "type": "Object", "tags": [], - "label": "filter", + "label": "field", "description": [], "signature": [ - "{ $state?: { store: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterStateStore", - "text": "FilterStateStore" - }, - "; } | undefined; meta: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterMeta", - "text": "FilterMeta" - }, - "; query?: Record | undefined; }" + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" ], - "path": "node_modules/@kbn/es-query/target_types/filters/build_filters/missing_filter.d.ts", + "path": "src/plugins/data_views/common/fields/utils.ts", "deprecated": false } ], @@ -49835,18 +50043,19 @@ "label": "isNestedField", "description": [], "signature": [ - "(field: ", + "(field: Pick<", { - "pluginId": "dataViews", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" }, - ") => boolean" + ", \"subType\">) => boolean" ], "path": "src/plugins/data_views/common/fields/utils.ts", "deprecated": false, + "returnComment": [], "children": [ { "parentPluginId": "data", @@ -49856,20 +50065,16 @@ "label": "field", "description": [], "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" - } + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" ], "path": "src/plugins/data_views/common/fields/utils.ts", - "deprecated": false, - "isRequired": true + "deprecated": false } ], - "returnComment": [], "initialIsOpen": false }, { @@ -51582,18 +51787,14 @@ { "parentPluginId": "data", "id": "def-common.FieldSpecExportFmt.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "src/plugins/data_views/common/types.ts", @@ -52005,10 +52206,6 @@ "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/utils.ts" }, - { - "plugin": "dataViews", - "path": "src/plugins/data_views/common/fields/utils.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/common/fields/data_view_field.ts" @@ -53003,14 +53200,6 @@ "plugin": "monitoring", "path": "x-pack/plugins/monitoring/public/lib/kuery.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts" @@ -53223,14 +53412,6 @@ "plugin": "timelines", "path": "x-pack/plugins/timelines/public/mock/index_pattern.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, { "plugin": "infra", "path": "x-pack/plugins/infra/target/types/public/containers/with_kuery_autocompletion.d.ts" @@ -53495,6 +53676,14 @@ "plugin": "infra", "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts" @@ -55604,7 +55793,7 @@ "section": "def-common.FilterMeta", "text": "FilterMeta" }, - "; exists?: { field: string; } | undefined; }" + "; query: { exists?: { field: string; } | undefined; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, @@ -57641,6 +57830,11 @@ ], "label": "IFieldSubType", "description": [], + "signature": [ + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional" + ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, "removeBy": "8.1", @@ -57713,19 +57907,19 @@ }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts" }, { "plugin": "dashboard", @@ -59166,9 +59360,9 @@ }, " & { meta: ", "MatchAllFilterMeta", - "; match_all: ", + "; query: { match_all: ", "QueryDslMatchAllQuery", - "; }" + "; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, @@ -59190,39 +59384,6 @@ "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "data", - "id": "def-common.MissingFilter", - "type": "Type", - "tags": [ - "deprecated" - ], - "label": "MissingFilter", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - " & { meta: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterMeta", - "text": "FilterMeta" - }, - "; missing: { field: string; }; }" - ], - "path": "src/plugins/data/common/es_query/index.ts", - "deprecated": true, - "removeBy": "8.1", - "references": [], - "initialIsOpen": false - }, { "parentPluginId": "data", "id": "def-common.OnError", @@ -59435,7 +59596,7 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; range: { [key: string]: ", + "; query: { range: { [key: string]: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -59443,7 +59604,7 @@ "section": "def-common.RangeFilterParams", "text": "RangeFilterParams" }, - "; }; }" + "; }; }; }" ], "path": "src/plugins/data/common/es_query/index.ts", "deprecated": true, diff --git a/api_docs/data.mdx b/api_docs/data.mdx index a8e983c6a6b24..0734f19d6c3eb 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3181 | 43 | 2796 | 48 | +| 3192 | 43 | 2807 | 48 | ## Client diff --git a/api_docs/data_autocomplete.mdx b/api_docs/data_autocomplete.mdx index 61c786d94839d..1eef9ef1c6932 100644 --- a/api_docs/data_autocomplete.mdx +++ b/api_docs/data_autocomplete.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3181 | 43 | 2796 | 48 | +| 3192 | 43 | 2807 | 48 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index cc5a593ab216b..bb88e5868b605 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3181 | 43 | 2796 | 48 | +| 3192 | 43 | 2807 | 48 | ## Client diff --git a/api_docs/data_search.json b/api_docs/data_search.json index 836984073c0e6..25ed62f473bd3 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -2277,13 +2277,7 @@ "label": "uiSettingsClient", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.IUiSettingsClient", - "text": "IUiSettingsClient" - } + "{ get: (key: string) => Promise; }" ], "path": "src/plugins/data/server/search/types.ts", "deprecated": false @@ -28577,7 +28571,7 @@ "label": "fn", "description": [], "signature": [ - "(input: null, args: Arguments) => any" + "(input: null, args: Arguments) => { type: \"kibana_filter\"; meta: { negate: boolean; alias: string; disabled: boolean; }; query: any; }" ], "path": "src/plugins/data/common/search/expressions/kibana_filter.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 8b89cd491c166..c7256296f1634 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3181 | 43 | 2796 | 48 | +| 3192 | 43 | 2807 | 48 | ## Client diff --git a/api_docs/data_ui.mdx b/api_docs/data_ui.mdx index 87c9d2ce08af0..39a1948d15c2c 100644 --- a/api_docs/data_ui.mdx +++ b/api_docs/data_ui.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3181 | 43 | 2796 | 48 | +| 3192 | 43 | 2807 | 48 | ## Client diff --git a/api_docs/data_views.json b/api_docs/data_views.json index d3160ea108718..c77aa02425e22 100644 --- a/api_docs/data_views.json +++ b/api_docs/data_views.json @@ -4736,35 +4736,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", @@ -13245,18 +13245,14 @@ { "parentPluginId": "dataViews", "id": "def-common.DataViewField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "src/plugins/data_views/common/fields/data_view_field.ts", @@ -13307,6 +13303,82 @@ "path": "src/plugins/data_views/common/fields/data_view_field.ts", "deprecated": false }, + { + "parentPluginId": "dataViews", + "id": "def-common.DataViewField.isSubtypeNested", + "type": "Function", + "tags": [], + "label": "isSubtypeNested", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "dataViews", + "id": "def-common.DataViewField.isSubtypeMulti", + "type": "Function", + "tags": [], + "label": "isSubtypeMulti", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "dataViews", + "id": "def-common.DataViewField.getSubtypeNested", + "type": "Function", + "tags": [], + "label": "getSubtypeNested", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "dataViews", + "id": "def-common.DataViewField.getSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getSubtypeMulti", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/data_view_field.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "dataViews", "id": "def-common.DataViewField.deleteCount", @@ -13331,13 +13403,9 @@ "description": [], "signature": [ "() => { count: number; script: string | undefined; lang: \"painless\" | \"expression\" | \"mustache\" | \"java\" | undefined; conflictDescriptions: Record | undefined; name: string; type: string; esTypes: string[] | undefined; scripted: boolean; searchable: boolean; aggregatable: boolean; readFromDocValues: boolean; subType: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; customLabel: string | undefined; }" ], "path": "src/plugins/data_views/common/fields/data_view_field.ts", @@ -16472,35 +16540,35 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx" + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts" }, { "plugin": "observability", @@ -19769,6 +19837,106 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "dataViews", + "id": "def-common.getFieldSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeMulti", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "dataViews", + "id": "def-common.getFieldSubtypeMulti.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "dataViews", + "id": "def-common.getFieldSubtypeNested", + "type": "Function", + "tags": [], + "label": "getFieldSubtypeNested", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "dataViews", + "id": "def-common.getFieldSubtypeNested.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "dataViews", "id": "def-common.getIndexPatternLoadMeta", @@ -19838,6 +20006,48 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "dataViews", + "id": "def-common.isMultiField", + "type": "Function", + "tags": [], + "label": "isMultiField", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => boolean" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "dataViews", + "id": "def-common.isMultiField.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" + ], + "path": "src/plugins/data_views/common/fields/utils.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "dataViews", "id": "def-common.isNestedField", @@ -19846,18 +20056,19 @@ "label": "isNestedField", "description": [], "signature": [ - "(field: ", + "(field: Pick<", { - "pluginId": "dataViews", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" }, - ") => boolean" + ", \"subType\">) => boolean" ], "path": "src/plugins/data_views/common/fields/utils.ts", "deprecated": false, + "returnComment": [], "children": [ { "parentPluginId": "dataViews", @@ -19867,20 +20078,16 @@ "label": "field", "description": [], "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.IFieldType", - "text": "IFieldType" - } + "{ subType?: ", + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined; }" ], "path": "src/plugins/data_views/common/fields/utils.ts", - "deprecated": false, - "isRequired": true + "deprecated": false } ], - "returnComment": [], "initialIsOpen": false } ], @@ -20754,18 +20961,14 @@ { "parentPluginId": "dataViews", "id": "def-common.FieldSpecExportFmt.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "src/plugins/data_views/common/types.ts", @@ -22411,14 +22614,6 @@ "plugin": "monitoring", "path": "x-pack/plugins/monitoring/public/lib/kuery.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts" @@ -22631,14 +22826,6 @@ "plugin": "timelines", "path": "x-pack/plugins/timelines/public/mock/index_pattern.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts" - }, { "plugin": "infra", "path": "x-pack/plugins/infra/target/types/public/containers/with_kuery_autocompletion.d.ts" @@ -22903,6 +23090,14 @@ "plugin": "infra", "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts" @@ -24924,19 +25119,19 @@ }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts" }, { "plugin": "visualizations", - "path": "src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts" + "path": "src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts" }, { "plugin": "dashboard", diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 373587de6f284..e907c075b9a8f 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 671 | 6 | 531 | 5 | +| 681 | 6 | 541 | 5 | ## Client diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 5e3c38eb354c1..a083c82e69d05 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -46,7 +46,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | dataViews, indexPatternManagement, data | - | | | dataViews, discover, ml, transform, canvas | - | | | dataViews, visTypeTimeseries, maps, lens, discover | - | -| | fleet, indexPatternFieldEditor, discover, dashboard, lens, ml, stackAlerts, indexPatternManagement, visTypeMetric, visTypePie, visTypeTable, visTypeTimeseries, visTypeXy, visTypeVislib | - | +| | fleet, indexPatternFieldEditor, discover, dashboard, lens, ml, stackAlerts, indexPatternManagement, visTypePie, visTypeTable, visTypeTimeseries, visTypeXy, visTypeVislib | - | | | reporting, visTypeTimeseries | - | | | data, lens, visTypeTimeseries, infra, maps, visTypeTimelion | - | | | dashboard, maps, graph, visualize | - | @@ -178,7 +178,6 @@ Safe to remove. | | | | | | -| | | | | | | | @@ -203,7 +202,6 @@ Safe to remove. | | | | | | -| | | | | | | | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 3714161b6c426..b33ab317ca885 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -205,12 +205,12 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternField), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPatternField), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPatternField)+ 2 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IIndexPattern), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=IIndexPattern), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=IIndexPattern) | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 14 more | 8.1 | +| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 13 more | 8.1 | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternSpec), [create_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/create_index_pattern.ts#:~:text=IndexPatternSpec), [create_index_pattern.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/routes/create_index_pattern.ts#:~:text=IndexPatternSpec) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternType) | - | | | [data_views.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_views.ts#:~:text=IndexPatternListItem), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternListItem) | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 14 more | 8.1 | +| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 13 more | 8.1 | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IIndexPattern), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=IIndexPattern), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=IIndexPattern) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IIndexPatternsApiClient), [index_patterns_api_client.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/index_patterns_api_client.ts#:~:text=IIndexPatternsApiClient), [index_patterns_api_client.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/index_patterns_api_client.ts#:~:text=IIndexPatternsApiClient) | - | @@ -230,7 +230,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getNonScriptedFields) | 8.1 | | | [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=getScriptedFields), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=getScriptedFields), [data_view.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.ts#:~:text=getScriptedFields), [data_views.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_views.ts#:~:text=getScriptedFields), [register_index_pattern_usage_collection.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/register_index_pattern_usage_collection.ts#:~:text=getScriptedFields), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getScriptedFields), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getScriptedFields), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getScriptedFields), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getScriptedFields), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=getScriptedFields)+ 1 more | 8.1 | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternField), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPatternField), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPatternField), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPatternField)+ 2 more | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 14 more | 8.1 | +| | [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/utils.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [data_view_field.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [field_list.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/field_list.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/types.ts#:~:text=IFieldType)+ 13 more | 8.1 | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [utils.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/utils.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes), [scripted_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/server/deprecations/scripted_fields.ts#:~:text=IndexPatternAttributes) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [data_view_field.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/fields/data_view_field.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern), [data_view.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/data_views/data_view.test.ts#:~:text=IndexPattern) | - | | | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/common/index.ts#:~:text=IndexPatternsService), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/data_views/public/index.ts#:~:text=IndexPatternsService) | - | @@ -678,7 +678,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=IndexPattern), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=IndexPattern), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=IndexPattern), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=IndexPattern), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=IndexPattern), [lens_attributes.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts#:~:text=IndexPattern), [lens_attributes.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts#:~:text=IndexPattern), [lens_attributes.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts#:~:text=IndexPattern), [default_configs.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts#:~:text=IndexPattern), [default_configs.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts#:~:text=IndexPattern)+ 38 more | - | | | [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec) | - | | | [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=indexPatterns), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=indexPatterns), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=indexPatterns), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/pages/alerts/index.tsx#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns), [observability_index_patterns.test.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts#:~:text=indexPatterns)+ 5 more | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters) | 8.1 | +| | [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=esFilters) | 8.1 | | | [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=ExistsFilter), [utils.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts#:~:text=ExistsFilter) | 8.1 | | | [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=Filter), [filter_value_label.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx#:~:text=Filter) | 8.1 | | | [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec), [observability_index_patterns.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts#:~:text=IndexPatternSpec) | - | @@ -836,15 +836,15 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=dashboardUrlGenerator), [use_risky_hosts_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts#:~:text=dashboardUrlGenerator), [use_risky_hosts_dashboard_links.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx#:~:text=dashboardUrlGenerator) | - | +| | [use_risky_hosts_dashboard_button_href.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts#:~:text=dashboardUrlGenerator), [use_risky_hosts_dashboard_links.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx#:~:text=dashboardUrlGenerator), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx#:~:text=dashboardUrlGenerator) | - | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern)+ 30 more | - | | | [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField) | - | -| | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IIndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern)+ 76 more | - | +| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 74 more | - | | | [middleware.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=indexPatterns), [plugin.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=indexPatterns), [dependencies_start_mock.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/mock/endpoint/dependencies_start_mock.ts#:~:text=indexPatterns) | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters)+ 15 more | 8.1 | +| | [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters), [epic.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts#:~:text=esFilters)+ 14 more | 8.1 | | | [expandable_network.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx#:~:text=esQuery), [expandable_network.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx#:~:text=esQuery), [events_viewer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx#:~:text=esQuery), [events_viewer.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx#:~:text=esQuery), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx#:~:text=esQuery)+ 30 more | 8.1 | | | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter)+ 163 more | 8.1 | -| | [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IIndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern)+ 162 more | - | +| | [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [action.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [index.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx#:~:text=IIndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/url_state/types.ts#:~:text=IIndexPattern)+ 158 more | - | | | [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField), [field_name_cell.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx#:~:text=IndexPatternField) | - | | | [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [helpers.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [entry_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern), [list_item.tsx](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx#:~:text=IndexPattern)+ 30 more | - | | | [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [store.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/types/timeline/store.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [model.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/model.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/actions.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [selectors.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/inputs/selectors.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter), [actions.ts](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts#:~:text=Filter)+ 163 more | 8.1 | @@ -983,14 +983,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex -## visTypeMetric - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/metric/public/plugin.ts#:~:text=fieldFormats) | - | - - - ## visTypePie | Deprecated API | Reference location(s) | Remove By | @@ -1101,7 +1093,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/plugin.ts#:~:text=indexPatterns) | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=esFilters), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=esFilters) | 8.1 | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | -| | [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE)+ 8 more | - | +| | [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [timeseries_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/timeseries_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [visualization_saved_object_migrations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE), [controls_references.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/utils/saved_visualization_references/controls_references.ts#:~:text=INDEX_PATTERN_SAVED_OBJECT_TYPE)+ 8 more | - | | | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=IndexPatternsContract) | - | | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern)+ 10 more | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | @@ -1109,7 +1101,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/vis_types/types.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [create_vis_embeddable_from_object.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=IndexPattern) | - | | | [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter), [visualize_embeddable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts#:~:text=Filter) | 8.1 | | | [find_list_items.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/find_list_items.ts#:~:text=SavedObjectLoader), [find_list_items.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/find_list_items.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader), [saved_visualizations.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/saved_visualizations.ts#:~:text=SavedObjectLoader), [services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectLoader), [services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectLoader) | - | -| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/types.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/types.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject) | - | +| | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject), [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObject) | - | | | [_saved_vis.ts](https://github.com/elastic/kibana/tree/master/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#:~:text=SavedObjectClass) | - | diff --git a/api_docs/elastic_apm_generator.json b/api_docs/elastic_apm_generator.json new file mode 100644 index 0000000000000..dc69c08bba5b2 --- /dev/null +++ b/api_docs/elastic_apm_generator.json @@ -0,0 +1,257 @@ +{ + "id": "@elastic/apm-generator", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.getObserverDefaults", + "type": "Function", + "tags": [], + "label": "getObserverDefaults", + "description": [], + "signature": [ + "() => Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>" + ], + "path": "packages/elastic-apm-generator/src/lib/defaults/get_observer_defaults.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.getSpanDestinationMetrics", + "type": "Function", + "tags": [], + "label": "getSpanDestinationMetrics", + "description": [], + "signature": [ + "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]) => Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]" + ], + "path": "packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.getSpanDestinationMetrics.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]" + ], + "path": "packages/elastic-apm-generator/src/lib/utils/get_span_destination_metrics.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.getTransactionMetrics", + "type": "Function", + "tags": [], + "label": "getTransactionMetrics", + "description": [], + "signature": [ + "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]) => { \"transaction.duration.histogram\": { values: number[]; counts: number[]; }; _doc_count: number; '@timestamp'?: number | undefined; 'agent.name'?: string | undefined; 'agent.version'?: string | undefined; 'ecs.version'?: string | undefined; 'event.outcome'?: string | undefined; 'event.ingested'?: number | undefined; 'metricset.name'?: string | undefined; 'observer.version'?: string | undefined; 'observer.version_major'?: number | undefined; 'parent.id'?: string | undefined; 'processor.event'?: string | undefined; 'processor.name'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; 'transaction.id'?: string | undefined; 'transaction.duration.us'?: number | undefined; 'transaction.sampled'?: true | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'service.node.name'?: string | undefined; 'span.id'?: string | undefined; 'span.name'?: string | undefined; 'span.type'?: string | undefined; 'span.subtype'?: string | undefined; 'span.duration.us'?: number | undefined; 'span.destination.service.name'?: string | undefined; 'span.destination.service.resource'?: string | undefined; 'span.destination.service.type'?: string | undefined; 'span.destination.service.response_time.sum.us'?: number | undefined; 'span.destination.service.response_time.count'?: number | undefined; }[]" + ], + "path": "packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.getTransactionMetrics.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]" + ], + "path": "packages/elastic-apm-generator/src/lib/utils/get_transaction_metrics.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.service", + "type": "Function", + "tags": [], + "label": "service", + "description": [], + "signature": [ + "(name: string, environment: string, agentName: string) => ", + "Service" + ], + "path": "packages/elastic-apm-generator/src/lib/service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.service.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-generator/src/lib/service.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.service.$2", + "type": "string", + "tags": [], + "label": "environment", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-generator/src/lib/service.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.service.$3", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/elastic-apm-generator/src/lib/service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.timerange", + "type": "Function", + "tags": [], + "label": "timerange", + "description": [], + "signature": [ + "(from: number, to: number) => ", + "Timerange" + ], + "path": "packages/elastic-apm-generator/src/lib/timerange.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.timerange.$1", + "type": "number", + "tags": [], + "label": "from", + "description": [], + "signature": [ + "number" + ], + "path": "packages/elastic-apm-generator/src/lib/timerange.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.timerange.$2", + "type": "number", + "tags": [], + "label": "to", + "description": [], + "signature": [ + "number" + ], + "path": "packages/elastic-apm-generator/src/lib/timerange.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.toElasticsearchOutput", + "type": "Function", + "tags": [], + "label": "toElasticsearchOutput", + "description": [], + "signature": [ + "(events: Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[], versionOverride: string | undefined) => { _index: string; _source: {}; }[]" + ], + "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.toElasticsearchOutput.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [], + "signature": [ + "Partial<{ '@timestamp': number; 'agent.name': string; 'agent.version': string; 'ecs.version': string; 'event.outcome': string; 'event.ingested': number; 'metricset.name': string; 'observer.version': string; 'observer.version_major': number; 'parent.id': string; 'processor.event': string; 'processor.name': string; 'trace.id': string; 'transaction.name': string; 'transaction.type': string; 'transaction.id': string; 'transaction.duration.us': number; 'transaction.duration.histogram': { values: number[]; counts: number[]; }; 'transaction.sampled': true; 'service.name': string; 'service.environment': string; 'service.node.name': string; 'span.id': string; 'span.name': string; 'span.type': string; 'span.subtype': string; 'span.duration.us': number; 'span.destination.service.name': string; 'span.destination.service.resource': string; 'span.destination.service.type': string; 'span.destination.service.response_time.sum.us': number; 'span.destination.service.response_time.count': number; }>[]" + ], + "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@elastic/apm-generator", + "id": "def-server.toElasticsearchOutput.$2", + "type": "string", + "tags": [], + "label": "versionOverride", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/elastic-apm-generator/src/lib/output/to_elasticsearch_output.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/elastic_apm_generator.mdx b/api_docs/elastic_apm_generator.mdx new file mode 100644 index 0000000000000..3b7667a6837b5 --- /dev/null +++ b/api_docs/elastic_apm_generator.mdx @@ -0,0 +1,27 @@ +--- +id: kibElasticApmGeneratorPluginApi +slug: /kibana-dev-docs/api/elastic-apm-generator +title: "@elastic/apm-generator" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @elastic/apm-generator plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-generator'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import elasticApmGeneratorObj from './elastic_apm_generator.json'; + +Elastic APM trace data generator + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 15 | 0 | 15 | 2 | + +## Server + +### Functions + + diff --git a/api_docs/event_log.json b/api_docs/event_log.json index 95ab6b473a0d3..1991fbff2589d 100644 --- a/api_docs/event_log.json +++ b/api_docs/event_log.json @@ -753,7 +753,7 @@ "label": "logEvent", "description": [], "signature": [ - "(properties: DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" + "(properties: DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -766,7 +766,7 @@ "label": "properties", "description": [], "signature": [ - "DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -783,7 +783,7 @@ "label": "startTiming", "description": [], "signature": [ - "(event: DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" + "(event: DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -796,7 +796,7 @@ "label": "event", "description": [], "signature": [ - "DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -813,7 +813,7 @@ "label": "stopTiming", "description": [], "signature": [ - "(event: DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" + "(event: DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => void" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -826,7 +826,7 @@ "label": "event", "description": [], "signature": [ - "DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, @@ -886,7 +886,7 @@ "label": "data", "description": [], "signature": [ - "(Readonly<{ tags?: string[] | undefined; kibana?: Readonly<{ version?: string | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}> | undefined)[]" + "(Readonly<{ tags?: string[] | undefined; kibana?: Readonly<{ version?: string | undefined; alert?: Readonly<{ rule?: Readonly<{ execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ total_indexing_duration_ms?: number | undefined; total_search_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}> | undefined)[]" ], "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", "deprecated": false @@ -905,7 +905,7 @@ "label": "IEvent", "description": [], "signature": [ - "DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, @@ -919,7 +919,7 @@ "label": "IValidatedEvent", "description": [], "signature": [ - "Readonly<{ tags?: string[] | undefined; kibana?: Readonly<{ version?: string | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}> | undefined" + "Readonly<{ tags?: string[] | undefined; kibana?: Readonly<{ version?: string | undefined; alert?: Readonly<{ rule?: Readonly<{ execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ total_indexing_duration_ms?: number | undefined; total_search_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, @@ -1138,7 +1138,7 @@ "label": "getLogger", "description": [], "signature": [ - "(properties: DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => ", + "(properties: DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined) => ", { "pluginId": "eventLog", "scope": "server", @@ -1158,7 +1158,7 @@ "label": "properties", "description": [], "signature": [ - "DeepPartial[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; uuid?: string | undefined; status_order?: number | undefined; } & {}> | undefined; } & {}> | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; rel?: string | undefined; namespace?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ scheduled?: string | undefined; schedule_delay?: number | undefined; } & {}> | undefined; space_ids?: string[] | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; message?: string | undefined; event?: Readonly<{ start?: string | undefined; type?: string[] | undefined; id?: string | undefined; end?: string | undefined; category?: string[] | undefined; url?: string | undefined; code?: string | undefined; original?: string | undefined; action?: string | undefined; kind?: string | undefined; severity?: number | undefined; outcome?: string | undefined; created?: string | undefined; dataset?: string | undefined; duration?: number | undefined; hash?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: number | undefined; timezone?: string | undefined; } & {}> | undefined; rule?: Readonly<{ id?: string | undefined; description?: string | undefined; name?: string | undefined; version?: string | undefined; license?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/server/types.ts", "deprecated": false, diff --git a/api_docs/expression_metric_vis.json b/api_docs/expression_metric_vis.json new file mode 100644 index 0000000000000..251e916797e7e --- /dev/null +++ b/api_docs/expression_metric_vis.json @@ -0,0 +1,837 @@ +{ + "id": "expressionMetricVis", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.metricVisFunction", + "type": "Function", + "tags": [], + "label": "metricVisFunction", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.MetricVisExpressionFunctionDefinition", + "text": "MetricVisExpressionFunctionDefinition" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.DimensionsVisParam", + "type": "Interface", + "tags": [], + "label": "DimensionsVisParam", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.DimensionsVisParam.metrics", + "type": "Array", + "tags": [], + "label": "metrics", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionValueBoxed", + "text": "ExpressionValueBoxed" + }, + "<\"vis_dimension\", { accessor: number | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DatatableColumn", + "text": "DatatableColumn" + }, + "; format: { id?: string | undefined; params: Record; }; }>[]" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.DimensionsVisParam.bucket", + "type": "CompoundType", + "tags": [], + "label": "bucket", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionValueBoxed", + "text": "ExpressionValueBoxed" + }, + "<\"vis_dimension\", { accessor: number | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DatatableColumn", + "text": "DatatableColumn" + }, + "; format: { id?: string | undefined; params: Record; }; }> | undefined" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments", + "type": "Interface", + "tags": [], + "label": "MetricArguments", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.percentageMode", + "type": "boolean", + "tags": [], + "label": "percentageMode", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.colorSchema", + "type": "Enum", + "tags": [], + "label": "colorSchema", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.colorMode", + "type": "CompoundType", + "tags": [], + "label": "colorMode", + "description": [], + "signature": [ + "\"Background\" | \"Labels\" | \"None\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.useRanges", + "type": "boolean", + "tags": [], + "label": "useRanges", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.invertColors", + "type": "boolean", + "tags": [], + "label": "invertColors", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.showLabels", + "type": "boolean", + "tags": [], + "label": "showLabels", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.bgFill", + "type": "string", + "tags": [], + "label": "bgFill", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.subText", + "type": "string", + "tags": [], + "label": "subText", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.colorRange", + "type": "Array", + "tags": [], + "label": "colorRange", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Range", + "text": "Range" + }, + "[]" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.font", + "type": "Object", + "tags": [], + "label": "font", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionTypeStyle", + "text": "ExpressionTypeStyle" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.metric", + "type": "Array", + "tags": [], + "label": "metric", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionValueBoxed", + "text": "ExpressionValueBoxed" + }, + "<\"vis_dimension\", { accessor: number | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DatatableColumn", + "text": "DatatableColumn" + }, + "; format: { id?: string | undefined; params: Record; }; }>[]" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricArguments.bucket", + "type": "CompoundType", + "tags": [], + "label": "bucket", + "description": [], + "signature": [ + "{ type: \"vis_dimension\"; } & { accessor: number | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DatatableColumn", + "text": "DatatableColumn" + }, + "; format: { id?: string | undefined; params: Record; }; }" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions", + "type": "Interface", + "tags": [], + "label": "MetricOptions", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.color", + "type": "string", + "tags": [], + "label": "color", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.bgColor", + "type": "string", + "tags": [], + "label": "bgColor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.lightText", + "type": "boolean", + "tags": [], + "label": "lightText", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricOptions.rowIndex", + "type": "number", + "tags": [], + "label": "rowIndex", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam", + "type": "Interface", + "tags": [], + "label": "MetricVisParam", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.percentageMode", + "type": "boolean", + "tags": [], + "label": "percentageMode", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.percentageFormatPattern", + "type": "string", + "tags": [], + "label": "percentageFormatPattern", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.useRanges", + "type": "boolean", + "tags": [], + "label": "useRanges", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.colorSchema", + "type": "Enum", + "tags": [], + "label": "colorSchema", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorSchemas", + "text": "ColorSchemas" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.metricColorMode", + "type": "CompoundType", + "tags": [], + "label": "metricColorMode", + "description": [], + "signature": [ + "\"Background\" | \"Labels\" | \"None\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.colorsRange", + "type": "Array", + "tags": [], + "label": "colorsRange", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Range", + "text": "Range" + }, + "[]" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.labels", + "type": "Object", + "tags": [], + "label": "labels", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.Labels", + "text": "Labels" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.invertColors", + "type": "boolean", + "tags": [], + "label": "invertColors", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisParam.style", + "type": "Object", + "tags": [], + "label": "style", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.Style", + "text": "Style" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisRenderConfig", + "type": "Interface", + "tags": [], + "label": "MetricVisRenderConfig", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisRenderConfig.visType", + "type": "string", + "tags": [], + "label": "visType", + "description": [], + "signature": [ + "\"metric\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisRenderConfig.visData", + "type": "Object", + "tags": [], + "label": "visData", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisRenderConfig.visConfig", + "type": "Object", + "tags": [], + "label": "visConfig", + "description": [], + "signature": [ + "{ metric: ", + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.MetricVisParam", + "text": "MetricVisParam" + }, + "; dimensions: ", + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.DimensionsVisParam", + "text": "DimensionsVisParam" + }, + "; }" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams", + "type": "Interface", + "tags": [], + "label": "VisParams", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams.addTooltip", + "type": "boolean", + "tags": [], + "label": "addTooltip", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams.addLegend", + "type": "boolean", + "tags": [], + "label": "addLegend", + "description": [], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams.dimensions", + "type": "Object", + "tags": [], + "label": "dimensions", + "description": [], + "signature": [ + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.DimensionsVisParam", + "text": "DimensionsVisParam" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams.metric", + "type": "Object", + "tags": [], + "label": "metric", + "description": [], + "signature": [ + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.MetricVisParam", + "text": "MetricVisParam" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.VisParams.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "\"metric\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.EXPRESSION_METRIC_NAME", + "type": "string", + "tags": [], + "label": "EXPRESSION_METRIC_NAME", + "description": [], + "signature": [ + "\"metricVis\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricInput", + "type": "Type", + "tags": [], + "label": "MetricInput", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + } + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.MetricVisExpressionFunctionDefinition", + "type": "Type", + "tags": [], + "label": "MetricVisExpressionFunctionDefinition", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionFunctionDefinition", + "text": "ExpressionFunctionDefinition" + }, + "<\"metricVis\", ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", ", + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.MetricArguments", + "text": "MetricArguments" + }, + ", ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionValueBoxed", + "text": "ExpressionValueBoxed" + }, + "<\"render\", { as: string; value: ", + { + "pluginId": "expressionMetricVis", + "scope": "common", + "docId": "kibExpressionMetricVisPluginApi", + "section": "def-common.MetricVisRenderConfig", + "text": "MetricVisRenderConfig" + }, + "; }>, ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExecutionContext", + "text": "ExecutionContext" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ", ", + { + "pluginId": "@kbn/utility-types", + "scope": "server", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-server.SerializableRecord", + "text": "SerializableRecord" + }, + ">>" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.PLUGIN_ID", + "type": "string", + "tags": [], + "label": "PLUGIN_ID", + "description": [], + "signature": [ + "\"expressionMetricVis\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/index.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "expressionMetricVis", + "id": "def-common.PLUGIN_NAME", + "type": "string", + "tags": [], + "label": "PLUGIN_NAME", + "description": [], + "signature": [ + "\"expressionMetricVis\"" + ], + "path": "src/plugins/chart_expressions/expression_metric/common/index.ts", + "deprecated": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx new file mode 100644 index 0000000000000..891d4d3f022d5 --- /dev/null +++ b/api_docs/expression_metric_vis.mdx @@ -0,0 +1,33 @@ +--- +id: kibExpressionMetricVisPluginApi +slug: /kibana-dev-docs/api/expressionMetricVis +title: "expressionMetricVis" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the expressionMetricVis plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import expressionMetricVisObj from './expression_metric_vis.json'; + +Expression MetricVis plugin adds a `metric` renderer and function to the expression plugin. The renderer will display the `metric` chart. + +Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 49 | 0 | 49 | 0 | + +## Common + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/fleet.json b/api_docs/fleet.json index b1a9d1bf89488..0bdb078d6f70d 100644 --- a/api_docs/fleet.json +++ b/api_docs/fleet.json @@ -731,6 +731,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -755,6 +779,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -779,6 +827,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -802,6 +874,30 @@ "section": "def-common.EpmPackageAdditions", "text": "EpmPackageAdditions" }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + ">" ], "path": "x-pack/plugins/fleet/public/types/ui_extensions.ts", @@ -2064,40 +2160,6 @@ ], "returnComment": [] }, - { - "parentPluginId": "fleet", - "id": "def-public.pagePathGetters.add_integration_from_policy", - "type": "Function", - "tags": [], - "label": "add_integration_from_policy", - "description": [ - "// TODO: This might need to be removed because we do not have a way to pick an integration in line anymore" - ], - "signature": [ - "({ policyId }: ", - "DynamicPagePathValues", - ") => [string, string]" - ], - "path": "x-pack/plugins/fleet/public/constants/page_paths.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "fleet", - "id": "def-public.pagePathGetters.add_integration_from_policy.$1", - "type": "Object", - "tags": [], - "label": "{ policyId }", - "description": [], - "signature": [ - "DynamicPagePathValues" - ], - "path": "x-pack/plugins/fleet/public/constants/page_paths.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, { "parentPluginId": "fleet", "id": "def-public.pagePathGetters.add_integration_to_policy", @@ -6342,6 +6404,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -6366,6 +6452,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -6390,6 +6500,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -6413,6 +6547,30 @@ "section": "def-common.EpmPackageAdditions", "text": "EpmPackageAdditions" }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | (Pick<", { "pluginId": "fleet", @@ -6439,7 +6597,33 @@ "section": "def-common.RegistryPackage", "text": "RegistryPackage" }, - ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })) => boolean" + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"installing\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"install_failed\"; } & { integration?: string | undefined; id: string; })) => boolean" ], "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", "deprecated": false, @@ -6480,8 +6664,8 @@ "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" + "section": "def-common.Installing", + "text": "Installing" }, "> | (Pick<", + ">> | ", { "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.RegistryPackage", - "text": "RegistryPackage" + "section": "def-common.Installed", + "text": "Installed" }, - ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", - "SavedObject", - "<", + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.NotInstalled", + "text": "NotInstalled" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" }, ">; } & { integration?: string | undefined; id: string; }) | (Pick<", { @@ -6573,7 +6853,33 @@ "section": "def-common.RegistryPackage", "text": "RegistryPackage" }, - ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"installing\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"install_failed\"; } & { integration?: string | undefined; id: string; })" ], "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", "deprecated": false, @@ -11069,6 +11375,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -11093,6 +11423,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -11117,6 +11471,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -11140,6 +11518,30 @@ "section": "def-common.EpmPackageAdditions", "text": "EpmPackageAdditions" }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + ">" ], "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", @@ -12090,7 +12492,7 @@ "label": "install_status", "description": [], "signature": [ - "\"installed\" | \"installing\"" + "\"installed\" | \"installing\" | \"install_failed\"" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false @@ -15771,6 +16173,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -15795,6 +16221,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -15819,6 +16269,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -15842,6 +16316,30 @@ "section": "def-common.EpmPackageAdditions", "text": "EpmPackageAdditions" }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + ">" ], "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", @@ -17120,7 +17618,7 @@ "label": "EpmPackageInstallStatus", "description": [], "signature": [ - "\"installed\" | \"installing\"" + "\"installed\" | \"installing\" | \"install_failed\"" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, @@ -17390,6 +17888,14 @@ "text": "Installed" }, " | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + " | ", { "pluginId": "fleet", "scope": "common", @@ -17397,6 +17903,14 @@ "section": "def-common.NotInstalled", "text": "NotInstalled" }, + " | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, "" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", @@ -17439,7 +17953,7 @@ "label": "InstallationStatus", "description": [], "signature": [ - "{ readonly Installed: \"installed\"; readonly NotInstalled: \"not_installed\"; }" + "{ readonly Installed: \"installed\"; readonly Installing: \"installing\"; readonly InstallFailed: \"install_failed\"; readonly NotInstalled: \"not_installed\"; }" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, @@ -17469,6 +17983,44 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "fleet", + "id": "def-common.InstallFailed", + "type": "Type", + "tags": [], + "label": "InstallFailed", + "description": [], + "signature": [ + "T & { status: \"install_failed\"; }" + ], + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.Installing", + "type": "Type", + "tags": [], + "label": "Installing", + "description": [], + "signature": [ + "T & { status: \"installing\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; }" + ], + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "fleet", "id": "def-common.InstallSource", @@ -17636,6 +18188,14 @@ "section": "def-common.KibanaAssetParts", "text": "KibanaAssetParts" }, + "[]; tag: ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.KibanaAssetParts", + "text": "KibanaAssetParts" + }, "[]; }" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", @@ -17869,6 +18429,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -17893,6 +18477,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -17917,6 +18525,30 @@ "text": "EpmPackageAdditions" }, ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installing", + "text": "Installing" + }, + "> | ", { "pluginId": "fleet", "scope": "common", @@ -17940,6 +18572,30 @@ "section": "def-common.EpmPackageAdditions", "text": "EpmPackageAdditions" }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.InstallFailed", + "text": "InstallFailed" + }, + ">" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", @@ -18001,7 +18657,33 @@ "section": "def-common.RegistryPackage", "text": "RegistryPackage" }, - ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"installing\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"title\" | \"description\" | \"icons\" | \"name\" | \"version\" | \"path\" | \"download\" | \"internal\" | \"data_streams\" | \"release\" | \"policy_templates\"> & { status: \"install_failed\"; } & { integration?: string | undefined; id: string; })" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, @@ -18155,6 +18837,22 @@ "section": "def-common.PackageList", "text": "PackageList" }, + "; installing: ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.PackageList", + "text": "PackageList" + }, + "; install_failed: ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.PackageList", + "text": "PackageList" + }, "; not_installed: ", { "pluginId": "fleet", @@ -20496,7 +21194,7 @@ "label": "installationStatuses", "description": [], "signature": [ - "{ readonly Installed: \"installed\"; readonly NotInstalled: \"not_installed\"; }" + "{ readonly Installed: \"installed\"; readonly Installing: \"installing\"; readonly InstallFailed: \"install_failed\"; readonly NotInstalled: \"not_installed\"; }" ], "path": "x-pack/plugins/fleet/common/constants/epm.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index bd467d94391f6..88d006982d0f0 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -18,7 +18,7 @@ Contact [Fleet](https://github.com/orgs/elastic/teams/fleet) for questions regar | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1207 | 15 | 1106 | 10 | +| 1207 | 15 | 1107 | 10 | ## Client diff --git a/api_docs/interactive_setup.json b/api_docs/interactive_setup.json index b10a3bd9f149a..bfccfd28388c4 100644 --- a/api_docs/interactive_setup.json +++ b/api_docs/interactive_setup.json @@ -265,6 +265,104 @@ } ], "misc": [ + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_CONFIGURE_FAILURE", + "type": "string", + "tags": [], + "label": "ERROR_CONFIGURE_FAILURE", + "description": [], + "signature": [ + "\"configure_failure\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_ELASTICSEARCH_CONNECTION_CONFIGURED", + "type": "string", + "tags": [], + "label": "ERROR_ELASTICSEARCH_CONNECTION_CONFIGURED", + "description": [], + "signature": [ + "\"elasticsearch_connection_configured\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_ENROLL_FAILURE", + "type": "string", + "tags": [], + "label": "ERROR_ENROLL_FAILURE", + "description": [], + "signature": [ + "\"enroll_failure\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_KIBANA_CONFIG_FAILURE", + "type": "string", + "tags": [], + "label": "ERROR_KIBANA_CONFIG_FAILURE", + "description": [], + "signature": [ + "\"kibana_config_failure\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_KIBANA_CONFIG_NOT_WRITABLE", + "type": "string", + "tags": [], + "label": "ERROR_KIBANA_CONFIG_NOT_WRITABLE", + "description": [], + "signature": [ + "\"kibana_config_not_writable\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_OUTSIDE_PREBOOT_STAGE", + "type": "string", + "tags": [], + "label": "ERROR_OUTSIDE_PREBOOT_STAGE", + "description": [], + "signature": [ + "\"outside_preboot_stage\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "interactiveSetup", + "id": "def-common.ERROR_PING_FAILURE", + "type": "string", + "tags": [], + "label": "ERROR_PING_FAILURE", + "description": [], + "signature": [ + "\"ping_failure\"" + ], + "path": "src/plugins/interactive_setup/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "interactiveSetup", "id": "def-common.VERIFICATION_CODE_LENGTH", diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index afc6ca7bb7e5a..b954d2c423543 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -18,7 +18,7 @@ Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-securit | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 19 | 0 | 9 | 0 | +| 26 | 0 | 16 | 0 | ## Common diff --git a/api_docs/kbn_config.json b/api_docs/kbn_config.json index 71827efb5cea0..f8a49fd358863 100644 --- a/api_docs/kbn_config.json +++ b/api_docs/kbn_config.json @@ -250,6 +250,45 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecationContext", + "type": "Interface", + "tags": [], + "label": "ConfigDeprecationContext", + "description": [ + "\nDeprecation context provided to {@link ConfigDeprecation | config deprecations}\n" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecationContext.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "The current Kibana version, e.g `7.16.1`, `8.0.0`" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecationContext.branch", + "type": "string", + "tags": [], + "label": "branch", + "description": [ + "The current Kibana branch, e.g `7.x`, `7.16`, `master`" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/config", "id": "def-server.ConfigDeprecationFactory", @@ -275,7 +314,13 @@ "(deprecatedKey: string, removeBy: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -340,7 +385,13 @@ "(deprecatedKey: string, removeBy: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -405,7 +456,13 @@ "(oldKey: string, newKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -470,7 +527,13 @@ "(oldKey: string, newKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -535,7 +598,13 @@ "(unusedKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -586,7 +655,13 @@ "(unusedKey: string, details?: Partial<", "DeprecatedConfigDetails", "> | undefined) => ", - "ConfigDeprecation" + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + } ], "path": "packages/kbn-config/src/deprecation/types.ts", "deprecated": false, @@ -773,6 +848,123 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation", + "type": "Type", + "tags": [], + "label": "ConfigDeprecation", + "description": [ + "\nConfiguration deprecation returned from {@link ConfigDeprecationProvider} that handles a single deprecation from the configuration.\n" + ], + "signature": [ + "(config: Readonly<{ [x: string]: any; }>, fromPath: string, addDeprecation: ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.AddConfigDeprecation", + "text": "AddConfigDeprecation" + }, + ", context: ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationContext", + "text": "ConfigDeprecationContext" + }, + ") => void | ", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationCommand", + "text": "ConfigDeprecationCommand" + } + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [ + "must not be mutated, return {@link ConfigDeprecationCommand} to change config shape." + ], + "signature": [ + "{ readonly [x: string]: any; }" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation.$2", + "type": "string", + "tags": [], + "label": "fromPath", + "description": [], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation.$3", + "type": "Function", + "tags": [], + "label": "addDeprecation", + "description": [], + "signature": [ + "(details: ", + "DeprecatedConfigDetails", + ") => void" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation.$3.$1", + "type": "Object", + "tags": [], + "label": "details", + "description": [], + "signature": [ + "DeprecatedConfigDetails" + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "@kbn/config", + "id": "def-server.ConfigDeprecation.$4", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecationContext", + "text": "ConfigDeprecationContext" + } + ], + "path": "packages/kbn-config/src/deprecation/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/config", "id": "def-server.ConfigDeprecationProvider", @@ -792,7 +984,13 @@ "text": "ConfigDeprecationFactory" }, ") => ", - "ConfigDeprecation", + { + "pluginId": "@kbn/config", + "scope": "server", + "docId": "kibKbnConfigPluginApi", + "section": "def-server.ConfigDeprecation", + "text": "ConfigDeprecation" + }, "[]" ], "path": "packages/kbn-config/src/deprecation/types.ts", diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 94939da9e8d78..4f4058ccd4509 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 57 | 0 | 42 | 2 | +| 66 | 0 | 46 | 1 | ## Server diff --git a/api_docs/kbn_es_query.json b/api_docs/kbn_es_query.json index f86c6a78eeb2d..0533bd7756849 100644 --- a/api_docs/kbn_es_query.json +++ b/api_docs/kbn_es_query.json @@ -1725,6 +1725,210 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getDataViewFieldSubtypeMulti", + "type": "Function", + "tags": [], + "label": "getDataViewFieldSubtypeMulti", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeMulti", + "text": "IFieldSubTypeMulti" + }, + " | undefined" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getDataViewFieldSubtypeMulti.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getDataViewFieldSubtypeNested", + "type": "Function", + "tags": [], + "label": "getDataViewFieldSubtypeNested", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.IFieldSubTypeNested", + "text": "IFieldSubTypeNested" + }, + " | undefined" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getDataViewFieldSubtypeNested.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isDataViewFieldSubtypeMulti", + "type": "Function", + "tags": [], + "label": "isDataViewFieldSubtypeMulti", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => boolean" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isDataViewFieldSubtypeMulti.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isDataViewFieldSubtypeNested", + "type": "Function", + "tags": [], + "label": "isDataViewFieldSubtypeNested", + "description": [], + "signature": [ + "(field: Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">) => boolean" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isDataViewFieldSubtypeNested.$1", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + ", \"subType\">" + ], + "path": "packages/kbn-es-query/src/utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.isExistsFilter", @@ -2010,60 +2214,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/es-query", - "id": "def-common.isMissingFilter", - "type": "Function", - "tags": [], - "label": "isMissingFilter", - "description": [], - "signature": [ - "(filter: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - ") => filter is ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.MissingFilter", - "text": "MissingFilter" - } - ], - "path": "packages/kbn-es-query/src/filters/build_filters/missing_filter.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "@kbn/es-query", - "id": "def-common.isMissingFilter.$1", - "type": "Object", - "tags": [], - "label": "filter", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - } - ], - "path": "packages/kbn-es-query/src/filters/build_filters/missing_filter.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [ - "`true` if a filter is an `MissingFilter`" - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/es-query", "id": "def-common.isPhraseFilter", @@ -3136,18 +3286,14 @@ { "parentPluginId": "@kbn/es-query", "id": "def-common.DataViewFieldBase.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "packages/kbn-es-query/src/es_query/types.ts", @@ -3279,38 +3425,49 @@ }, { "parentPluginId": "@kbn/es-query", - "id": "def-common.IFieldSubType", + "id": "def-common.IFieldSubTypeMulti", "type": "Interface", "tags": [], - "label": "IFieldSubType", - "description": [ - "\nA field's sub type" - ], + "label": "IFieldSubTypeMulti", + "description": [], "path": "packages/kbn-es-query/src/es_query/types.ts", "deprecated": false, "children": [ { "parentPluginId": "@kbn/es-query", - "id": "def-common.IFieldSubType.multi", + "id": "def-common.IFieldSubTypeMulti.multi", "type": "Object", "tags": [], "label": "multi", "description": [], "signature": [ - "{ parent: string; } | undefined" + "{ parent: string; }" ], "path": "packages/kbn-es-query/src/es_query/types.ts", "deprecated": false - }, + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.IFieldSubTypeNested", + "type": "Interface", + "tags": [], + "label": "IFieldSubTypeNested", + "description": [], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "children": [ { "parentPluginId": "@kbn/es-query", - "id": "def-common.IFieldSubType.nested", + "id": "def-common.IFieldSubTypeNested.nested", "type": "Object", "tags": [], "label": "nested", "description": [], "signature": [ - "{ path: string; } | undefined" + "{ path: string; }" ], "path": "packages/kbn-es-query/src/es_query/types.ts", "deprecated": false @@ -3665,7 +3822,7 @@ "section": "def-common.FilterMeta", "text": "FilterMeta" }, - "; exists?: { field: string; } | undefined; }" + "; query: { exists?: { field: string; } | undefined; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/exists_filter.ts", "deprecated": false, @@ -3697,14 +3854,6 @@ "text": "MatchAllFilter" }, " | ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.MissingFilter", - "text": "MissingFilter" - }, - " | ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -3777,6 +3926,24 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.IFieldSubType", + "type": "Type", + "tags": [], + "label": "IFieldSubType", + "description": [ + "\nA field's sub type" + ], + "signature": [ + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional" + ], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.IndexPatternBase", @@ -3840,43 +4007,14 @@ }, " & { meta: ", "MatchAllFilterMeta", - "; match_all: ", + "; query: { match_all: ", "QueryDslMatchAllQuery", - "; }" + "; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/match_all_filter.ts", "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/es-query", - "id": "def-common.MissingFilter", - "type": "Type", - "tags": [], - "label": "MissingFilter", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - " & { meta: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.FilterMeta", - "text": "FilterMeta" - }, - "; missing: { field: string; }; }" - ], - "path": "packages/kbn-es-query/src/filters/build_filters/missing_filter.ts", - "deprecated": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/es-query", "id": "def-common.PhraseFilter", @@ -3995,7 +4133,7 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; range: { [key: string]: ", + "; query: { range: { [key: string]: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -4003,7 +4141,7 @@ "section": "def-common.RangeFilterParams", "text": "RangeFilterParams" }, - "; }; }" + "; }; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/range_filter.ts", "deprecated": false, @@ -4086,9 +4224,9 @@ "section": "def-common.RangeFilterMeta", "text": "RangeFilterMeta" }, - "; script: { script: ", + "; query: { script: { script: ", "InlineScript", - "; }; }" + "; }; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/range_filter.ts", "deprecated": false, diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 0ba50032b3634..be44bd1e5a9a4 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 198 | 2 | 146 | 12 | +| 205 | 2 | 153 | 14 | ## Common diff --git a/api_docs/kbn_logging.json b/api_docs/kbn_logging.json index 32ab4bac1ffac..efb4d27831199 100644 --- a/api_docs/kbn_logging.json +++ b/api_docs/kbn_logging.json @@ -706,7 +706,7 @@ "EcsHttp", " | undefined; log?: Pick<", "EcsLog", - ", \"origin\" | \"original\" | \"file\" | \"syslog\"> | undefined; network?: ", + ", \"origin\" | \"file\" | \"syslog\"> | undefined; network?: ", "EcsNetwork", " | undefined; observer?: ", "EcsObserver", diff --git a/api_docs/kbn_monaco.json b/api_docs/kbn_monaco.json index fd755fda853ec..b87619f900457 100644 --- a/api_docs/kbn_monaco.json +++ b/api_docs/kbn_monaco.json @@ -32,8 +32,8 @@ "pluginId": "@kbn/monaco", "scope": "common", "docId": "kibKbnMonacoPluginApi", - "section": "def-common.LangModule", - "text": "LangModule" + "section": "def-common.LangModuleType", + "text": "LangModuleType" }, ") => void" ], @@ -52,8 +52,8 @@ "pluginId": "@kbn/monaco", "scope": "common", "docId": "kibKbnMonacoPluginApi", - "section": "def-common.LangModule", - "text": "LangModule" + "section": "def-common.LangModuleType", + "text": "LangModuleType" } ], "path": "packages/kbn-monaco/src/helpers.ts", @@ -68,26 +68,26 @@ "interfaces": [ { "parentPluginId": "@kbn/monaco", - "id": "def-common.CompleteLangModule", + "id": "def-common.CompleteLangModuleType", "type": "Interface", "tags": [], - "label": "CompleteLangModule", + "label": "CompleteLangModuleType", "description": [], "signature": [ { "pluginId": "@kbn/monaco", "scope": "common", "docId": "kibKbnMonacoPluginApi", - "section": "def-common.CompleteLangModule", - "text": "CompleteLangModule" + "section": "def-common.CompleteLangModuleType", + "text": "CompleteLangModuleType" }, " extends ", { "pluginId": "@kbn/monaco", "scope": "common", "docId": "kibKbnMonacoPluginApi", - "section": "def-common.LangModule", - "text": "LangModule" + "section": "def-common.LangModuleType", + "text": "LangModuleType" } ], "path": "packages/kbn-monaco/src/types.ts", @@ -95,7 +95,7 @@ "children": [ { "parentPluginId": "@kbn/monaco", - "id": "def-common.CompleteLangModule.languageConfiguration", + "id": "def-common.CompleteLangModuleType.languageConfiguration", "type": "Object", "tags": [], "label": "languageConfiguration", @@ -109,7 +109,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.CompleteLangModule.getSuggestionProvider", + "id": "def-common.CompleteLangModuleType.getSuggestionProvider", "type": "Object", "tags": [], "label": "getSuggestionProvider", @@ -122,7 +122,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.CompleteLangModule.getSyntaxErrors", + "id": "def-common.CompleteLangModuleType.getSyntaxErrors", "type": "Object", "tags": [], "label": "getSyntaxErrors", @@ -138,17 +138,17 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule", + "id": "def-common.LangModuleType", "type": "Interface", "tags": [], - "label": "LangModule", + "label": "LangModuleType", "description": [], "path": "packages/kbn-monaco/src/types.ts", "deprecated": false, "children": [ { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule.ID", + "id": "def-common.LangModuleType.ID", "type": "string", "tags": [], "label": "ID", @@ -158,7 +158,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule.lexerRules", + "id": "def-common.LangModuleType.lexerRules", "type": "Object", "tags": [], "label": "lexerRules", @@ -172,7 +172,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule.languageConfiguration", + "id": "def-common.LangModuleType.languageConfiguration", "type": "Object", "tags": [], "label": "languageConfiguration", @@ -186,7 +186,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule.getSuggestionProvider", + "id": "def-common.LangModuleType.getSuggestionProvider", "type": "Object", "tags": [], "label": "getSuggestionProvider", @@ -199,7 +199,7 @@ }, { "parentPluginId": "@kbn/monaco", - "id": "def-common.LangModule.getSyntaxErrors", + "id": "def-common.LangModuleType.getSyntaxErrors", "type": "Object", "tags": [], "label": "getSyntaxErrors", @@ -245,10 +245,136 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem", + "type": "Interface", + "tags": [], + "label": "PainlessCompletionItem", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem.kind", + "type": "CompoundType", + "tags": [], + "label": "kind", + "description": [], + "signature": [ + "\"type\" | \"keyword\" | \"field\" | \"property\" | \"method\" | \"class\" | \"constructor\"" + ], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem.documentation", + "type": "string", + "tags": [], + "label": "documentation", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem.insertText", + "type": "string", + "tags": [], + "label": "insertText", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionItem.insertTextAsSnippet", + "type": "CompoundType", + "tags": [], + "label": "insertTextAsSnippet", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionResult", + "type": "Interface", + "tags": [], + "label": "PainlessCompletionResult", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionResult.isIncomplete", + "type": "boolean", + "tags": [], + "label": "isIncomplete", + "description": [], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionResult.suggestions", + "type": "Array", + "tags": [], + "label": "suggestions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/monaco", + "scope": "common", + "docId": "kibKbnMonacoPluginApi", + "section": "def-common.PainlessCompletionItem", + "text": "PainlessCompletionItem" + }, + "[]" + ], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false } ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.PainlessCompletionKind", + "type": "Type", + "tags": [], + "label": "PainlessCompletionKind", + "description": [], + "signature": [ + "\"type\" | \"keyword\" | \"field\" | \"property\" | \"method\" | \"class\" | \"constructor\"" + ], + "path": "packages/kbn-monaco/src/painless/types.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/monaco", "id": "def-common.PainlessContext", diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 4d205f38a7609..08c7f95ee4f43 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 28 | 0 | 28 | 3 | +| 38 | 0 | 38 | 3 | ## Common diff --git a/api_docs/kbn_optimizer.json b/api_docs/kbn_optimizer.json index 2e0fe2fb179ba..e03d89f200ba4 100644 --- a/api_docs/kbn_optimizer.json +++ b/api_docs/kbn_optimizer.json @@ -314,6 +314,61 @@ } ], "functions": [ + { + "parentPluginId": "@kbn/optimizer", + "id": "def-server.logOptimizerProgress", + "type": "Function", + "tags": [], + "label": "logOptimizerProgress", + "description": [], + "signature": [ + "(log: ", + { + "pluginId": "@kbn/dev-utils", + "scope": "server", + "docId": "kibKbnDevUtilsPluginApi", + "section": "def-server.ToolingLog", + "text": "ToolingLog" + }, + ") => ", + "MonoTypeOperatorFunction", + "<", + { + "pluginId": "@kbn/optimizer", + "scope": "server", + "docId": "kibKbnOptimizerPluginApi", + "section": "def-server.OptimizerUpdate", + "text": "OptimizerUpdate" + }, + ">" + ], + "path": "packages/kbn-optimizer/src/log_optimizer_progress.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/optimizer", + "id": "def-server.logOptimizerProgress.$1", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "signature": [ + { + "pluginId": "@kbn/dev-utils", + "scope": "server", + "docId": "kibKbnDevUtilsPluginApi", + "section": "def-server.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-optimizer/src/log_optimizer_progress.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/optimizer", "id": "def-server.logOptimizerState", diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index e59e362121899..e4af57faa7907 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 42 | 0 | 42 | 9 | +| 44 | 0 | 44 | 9 | ## Server diff --git a/api_docs/kbn_securitysolution_list_utils.json b/api_docs/kbn_securitysolution_list_utils.json index bfc009f17df0a..5b956218f5ac8 100644 --- a/api_docs/kbn_securitysolution_list_utils.json +++ b/api_docs/kbn_securitysolution_list_utils.json @@ -2774,7 +2774,7 @@ "label": "bool", "description": [], "signature": [ - "{ must?: unknown; must_not?: unknown; should?: unknown[] | undefined; filter?: unknown; minimum_should_match?: number | undefined; }" + "QueryDslBoolQuery" ], "path": "packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts", "deprecated": false @@ -3265,7 +3265,7 @@ "label": "nested", "description": [], "signature": [ - "{ path: string; query: unknown; score_mode: string; }" + "QueryDslNestedQuery" ], "path": "packages/kbn-securitysolution-list-utils/src/build_exception_filter/index.ts", "deprecated": false diff --git a/api_docs/kbn_typed_react_router_config.json b/api_docs/kbn_typed_react_router_config.json index aaa1c025910c6..3f9fa9c74d723 100644 --- a/api_docs/kbn_typed_react_router_config.json +++ b/api_docs/kbn_typed_react_router_config.json @@ -165,7 +165,7 @@ "label": "Outlet", "description": [], "signature": [ - "() => React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" + "() => React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | null" ], "path": "packages/kbn-typed-react-router-config/src/outlet.tsx", "deprecated": false, @@ -173,6 +173,61 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.OutletContextProvider", + "type": "Function", + "tags": [], + "label": "OutletContextProvider", + "description": [], + "signature": [ + "({\n element,\n children,\n}: { element: React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>; children: React.ReactNode; }) => JSX.Element" + ], + "path": "packages/kbn-typed-react-router-config/src/outlet.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.OutletContextProvider.$1", + "type": "Object", + "tags": [], + "label": "{\n element,\n children,\n}", + "description": [], + "path": "packages/kbn-typed-react-router-config/src/outlet.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.OutletContextProvider.$1.element", + "type": "Object", + "tags": [], + "label": "element", + "description": [], + "signature": [ + "React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" + ], + "path": "packages/kbn-typed-react-router-config/src/outlet.tsx", + "deprecated": false + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.OutletContextProvider.$1.children", + "type": "CompoundType", + "tags": [], + "label": "children", + "description": [], + "signature": [ + "string | number | boolean | {} | React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | React.ReactNodeArray | React.ReactPortal | null | undefined" + ], + "path": "packages/kbn-typed-react-router-config/src/outlet.tsx", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/typed-react-router-config", "id": "def-common.route", @@ -236,7 +291,7 @@ "section": "def-common.Route", "text": "Route" }, - "[]>; children: React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>; }) => JSX.Element" + "[]>; children: React.ReactNode; }) => JSX.Element" ], "path": "packages/kbn-typed-react-router-config/src/use_router.tsx", "deprecated": false, @@ -282,12 +337,12 @@ { "parentPluginId": "@kbn/typed-react-router-config", "id": "def-common.RouterContextProvider.$1.children", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "children", "description": [], "signature": [ - "React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" + "string | number | boolean | {} | React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | React.ReactNodeArray | React.ReactPortal | null | undefined" ], "path": "packages/kbn-typed-react-router-config/src/use_router.tsx", "deprecated": false @@ -340,7 +395,7 @@ }, "[]>; history: ", "History", - "; children: React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>; }) => JSX.Element" + "; children: React.ReactNode; }) => JSX.Element" ], "path": "packages/kbn-typed-react-router-config/src/router_provider.tsx", "deprecated": false, @@ -400,12 +455,12 @@ { "parentPluginId": "@kbn/typed-react-router-config", "id": "def-common.RouterProvider.$1.children", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "children", "description": [], "signature": [ - "React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" + "string | number | boolean | {} | React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | React.ReactNodeArray | React.ReactPortal | null | undefined" ], "path": "packages/kbn-typed-react-router-config/src/router_provider.tsx", "deprecated": false @@ -2027,6 +2082,44 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.Router.getRoutesToMatch", + "type": "Function", + "tags": [], + "label": "getRoutesToMatch", + "description": [], + "signature": [ + "(path: string) => ", + { + "pluginId": "@kbn/typed-react-router-config", + "scope": "common", + "docId": "kibKbnTypedReactRouterConfigPluginApi", + "section": "def-common.FlattenRoutesOf", + "text": "FlattenRoutesOf" + }, + "" + ], + "path": "packages/kbn-typed-react-router-config/src/types/index.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.Router.getRoutesToMatch.$1", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-typed-react-router-config/src/types/index.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false @@ -2034,6 +2127,24 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-common.FlattenRoutesOf", + "type": "Type", + "tags": [], + "label": "FlattenRoutesOf", + "description": [], + "signature": [ + "Pick<", + "ValuesType", + ">, Exclude>, \"parents\">>[]" + ], + "path": "packages/kbn-typed-react-router-config/src/types/index.ts", + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/typed-react-router-config", "id": "def-common.Match", diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 9a665ee8e676f..a25fa737996c5 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 71 | 0 | 71 | 1 | +| 78 | 0 | 78 | 1 | ## Common diff --git a/api_docs/kibana_utils.json b/api_docs/kibana_utils.json index 6411b8b7e1cee..744c735e94d68 100644 --- a/api_docs/kibana_utils.json +++ b/api_docs/kibana_utils.json @@ -1486,7 +1486,7 @@ "label": "createGetterSetter", "description": [], "signature": [ - "(name: string) => [", + "(name: string, isValueRequired?: boolean) => [", { "pluginId": "kibanaUtils", "scope": "common", @@ -1520,6 +1520,20 @@ "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", "deprecated": false, "isRequired": true + }, + { + "parentPluginId": "kibanaUtils", + "id": "def-public.createGetterSetter.$2", + "type": "boolean", + "tags": [], + "label": "isValueRequired", + "description": [], + "signature": [ + "boolean" + ], + "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", + "deprecated": false, + "isRequired": true } ], "returnComment": [], @@ -7113,7 +7127,7 @@ "label": "createGetterSetter", "description": [], "signature": [ - "(name: string) => [", + "(name: string, isValueRequired?: boolean) => [", { "pluginId": "kibanaUtils", "scope": "common", @@ -7147,6 +7161,20 @@ "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", "deprecated": false, "isRequired": true + }, + { + "parentPluginId": "kibanaUtils", + "id": "def-server.createGetterSetter.$2", + "type": "boolean", + "tags": [], + "label": "isValueRequired", + "description": [], + "signature": [ + "boolean" + ], + "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", + "deprecated": false, + "isRequired": true } ], "returnComment": [], @@ -8686,7 +8714,7 @@ "label": "createGetterSetter", "description": [], "signature": [ - "(name: string) => [", + "(name: string, isValueRequired?: boolean) => [", { "pluginId": "kibanaUtils", "scope": "common", @@ -8720,6 +8748,20 @@ "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", "deprecated": false, "isRequired": true + }, + { + "parentPluginId": "kibanaUtils", + "id": "def-common.createGetterSetter.$2", + "type": "boolean", + "tags": [], + "label": "isValueRequired", + "description": [], + "signature": [ + "boolean" + ], + "path": "src/plugins/kibana_utils/common/create_getter_setter.ts", + "deprecated": false, + "isRequired": true } ], "returnComment": [], diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index b428f08aca7e1..807999db2f4e9 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 603 | 3 | 410 | 8 | +| 606 | 3 | 413 | 8 | ## Client diff --git a/api_docs/lens.json b/api_docs/lens.json index 9d9591af006ac..18f6f3320f624 100644 --- a/api_docs/lens.json +++ b/api_docs/lens.json @@ -1807,6 +1807,19 @@ ], "path": "x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts", "deprecated": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.textVisibility", + "type": "CompoundType", + "tags": [], + "label": "textVisibility", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts", + "deprecated": false } ], "initialIsOpen": false diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 6165c3ec65d5d..9232e5da09428 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -18,7 +18,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 252 | 0 | 234 | 24 | +| 253 | 0 | 235 | 24 | ## Client diff --git a/api_docs/maps.json b/api_docs/maps.json index b5ff309ccbbbf..3b4551b099afb 100644 --- a/api_docs/maps.json +++ b/api_docs/maps.json @@ -2962,7 +2962,7 @@ "section": "def-public.LayerWizard", "text": "LayerWizard" }, - ") => Promise" + ") => void" ], "path": "x-pack/plugins/maps/public/api/setup_api.ts", "deprecated": false, @@ -3000,7 +3000,7 @@ "signature": [ "(entry: ", "SourceRegistryEntry", - ") => Promise" + ") => void" ], "path": "x-pack/plugins/maps/public/api/setup_api.ts", "deprecated": false, diff --git a/api_docs/observability.json b/api_docs/observability.json index 5887895476e3e..aa66c500c05e5 100644 --- a/api_docs/observability.json +++ b/api_docs/observability.json @@ -238,9 +238,11 @@ "label": "FilterValueLabel", "description": [], "signature": [ - "({\n label,\n field,\n value,\n negate,\n indexPattern,\n invertFilter,\n removeFilter,\n allowExclusion = true,\n}: Props) => JSX.Element | null" + "(props: ", + "FilterValueLabelProps", + ") => JSX.Element" ], - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx", + "path": "x-pack/plugins/observability/public/components/shared/index.tsx", "deprecated": false, "children": [ { @@ -248,12 +250,12 @@ "id": "def-public.FilterValueLabel.$1", "type": "Object", "tags": [], - "label": "{\n label,\n field,\n value,\n negate,\n indexPattern,\n invertFilter,\n removeFilter,\n allowExclusion = true,\n}", + "label": "props", "description": [], "signature": [ - "Props" + "FilterValueLabelProps" ], - "path": "x-pack/plugins/observability/public/components/shared/filter_value_label/filter_value_label.tsx", + "path": "x-pack/plugins/observability/public/components/shared/index.tsx", "deprecated": false, "isRequired": true } @@ -386,6 +388,48 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-public.InspectorContextProvider", + "type": "Function", + "tags": [], + "label": "InspectorContextProvider", + "description": [], + "signature": [ + "({ children }: { children: React.ReactNode; }) => JSX.Element" + ], + "path": "x-pack/plugins/observability/public/context/inspector/inspector_context.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-public.InspectorContextProvider.$1", + "type": "Object", + "tags": [], + "label": "{ children }", + "description": [], + "path": "x-pack/plugins/observability/public/context/inspector/inspector_context.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-public.InspectorContextProvider.$1.children", + "type": "CompoundType", + "tags": [], + "label": "children", + "description": [], + "signature": [ + "string | number | boolean | {} | React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | React.ReactNodeArray | React.ReactPortal | null | undefined" + ], + "path": "x-pack/plugins/observability/public/context/inspector/inspector_context.tsx", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-public.LazyAlertsFlyout", @@ -833,6 +877,23 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-public.useInspectorContext", + "type": "Function", + "tags": [], + "label": "useInspectorContext", + "description": [], + "signature": [ + "() => ", + "InspectorContextValue" + ], + "path": "x-pack/plugins/observability/public/context/inspector/use_inspector_context.tsx", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-public.useTheme", @@ -3660,6 +3721,173 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse", + "type": "Function", + "tags": [], + "label": "getInspectResponse", + "description": [ + "\nCreate a formatted response to be sent in the _inspect key for use in the\ninspector." + ], + "signature": [ + "({\n esError,\n esRequestParams,\n esRequestStatus,\n esResponse,\n kibanaRequest,\n operationName,\n startTime,\n}: { esError: ", + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.WrappedElasticsearchClientError", + "text": "WrappedElasticsearchClientError" + }, + " | null; esRequestParams: Record; esRequestStatus: ", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.RequestStatus", + "text": "RequestStatus" + }, + "; esResponse: any; kibanaRequest: ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreHttpPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "; operationName: string; startTime: number; }) => ", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Request", + "text": "Request" + } + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1", + "type": "Object", + "tags": [], + "label": "{\n esError,\n esRequestParams,\n esRequestStatus,\n esResponse,\n kibanaRequest,\n operationName,\n startTime,\n}", + "description": [], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.esError", + "type": "CompoundType", + "tags": [], + "label": "esError", + "description": [], + "signature": [ + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.WrappedElasticsearchClientError", + "text": "WrappedElasticsearchClientError" + }, + " | null" + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.esRequestParams", + "type": "Object", + "tags": [], + "label": "esRequestParams", + "description": [], + "signature": [ + "{ [x: string]: any; }" + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.esRequestStatus", + "type": "Enum", + "tags": [], + "label": "esRequestStatus", + "description": [], + "signature": [ + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.RequestStatus", + "text": "RequestStatus" + } + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.esResponse", + "type": "Any", + "tags": [], + "label": "esResponse", + "description": [], + "signature": [ + "any" + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.kibanaRequest", + "type": "Object", + "tags": [], + "label": "kibanaRequest", + "description": [], + "signature": [ + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreHttpPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.operationName", + "type": "string", + "tags": [], + "label": "operationName", + "description": [], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + }, + { + "parentPluginId": "observability", + "id": "def-server.getInspectResponse.$1.startTime", + "type": "number", + "tags": [], + "label": "startTime", + "description": [], + "path": "x-pack/plugins/observability/server/utils/get_inspect_response.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-server.kqlQuery", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 4b7ac03a70e14..57228c938c386 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -18,7 +18,7 @@ Contact [Observability UI](https://github.com/orgs/elastic/teams/observability-u | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 245 | 0 | 245 | 10 | +| 258 | 1 | 257 | 12 | ## Client diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index ab85e02919102..533a86b9e806f 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -12,13 +12,13 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 201 | 156 | 32 | +| 202 | 158 | 32 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 24158 | 274 | 19590 | 1579 | +| 24409 | 277 | 19821 | 1585 | ## Plugin Directory @@ -27,23 +27,23 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 125 | 0 | 125 | 8 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 23 | 0 | 22 | 1 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 249 | 0 | 241 | 17 | -| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | - | 42 | 0 | 42 | 37 | +| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 42 | 0 | 42 | 37 | | | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | - | 6 | 0 | 6 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 77 | 1 | 66 | 2 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | | | [Security Solution Threat Hunting](https://github.com/orgs/elastic/teams/security-threat-hunting) | The Case management system in Kibana | 475 | 0 | 431 | 14 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 223 | 2 | 192 | 3 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 285 | 4 | 253 | 3 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 22 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 9 | 0 | 9 | 1 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2293 | 27 | 1020 | 29 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2300 | 27 | 1019 | 29 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 85 | 1 | 78 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 145 | 1 | 132 | 10 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 51 | 0 | 50 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3181 | 43 | 2796 | 48 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3192 | 43 | 2807 | 48 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Enhanced data plugin. (See src/plugins/data.) Enhances the main data plugin with a search session management UI. Includes a reusable search session indicator component to use in other applications. Exposes routes for managing search sessions. Includes a service that monitors, updates, and cleans up search session saved objects. | 16 | 0 | 16 | 2 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 671 | 6 | 531 | 5 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 681 | 6 | 541 | 5 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 80 | 5 | 80 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 10 | 0 | 8 | 2 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 82 | 0 | 56 | 6 | @@ -57,6 +57,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'error' renderer to expressions | 12 | 0 | 12 | 2 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'image' function and renderer to expressions | 24 | 0 | 24 | 0 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'metric' function and renderer to expressions | 30 | 0 | 25 | 0 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression MetricVis plugin adds a `metric` renderer and function to the expression plugin. The renderer will display the `metric` chart. | 49 | 0 | 49 | 0 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'repeatImage' function and renderer to expressions | 30 | 0 | 30 | 0 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'revealImage' function and renderer to expressions | 12 | 0 | 12 | 3 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 143 | 0 | 143 | 0 | @@ -65,7 +66,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 216 | 0 | 98 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 288 | 7 | 250 | 3 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 129 | 4 | 129 | 1 | -| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1207 | 15 | 1106 | 10 | +| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1207 | 15 | 1107 | 10 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | globalSearchProviders | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | @@ -81,13 +82,13 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | ingestPipelines | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | inputControlVis | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 123 | 6 | 96 | 4 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 19 | 0 | 9 | 0 | +| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 26 | 0 | 16 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 48 | 1 | 45 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 297 | 8 | 260 | 5 | | kibanaUsageCollection | [Kibana Telemtry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 0 | 0 | 0 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 603 | 3 | 410 | 8 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 252 | 0 | 234 | 24 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 606 | 3 | 413 | 8 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 253 | 0 | 235 | 24 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 8 | 0 | 8 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 3 | 0 | 3 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 8 | @@ -101,7 +102,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Stack Monitoring](https://github.com/orgs/elastic/teams/stack-monitoring-ui) | - | 10 | 0 | 10 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 31 | 0 | 31 | 2 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | -| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 245 | 0 | 245 | 10 | +| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 258 | 1 | 257 | 12 | | | [Security asset management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 11 | 0 | 11 | 0 | | painlessLab | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 178 | 3 | 151 | 5 | @@ -117,11 +118,10 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 22 | 0 | 17 | 1 | | searchprofiler | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 113 | 0 | 51 | 7 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin exposes a limited set of security functionality to OSS plugins. | 12 | 0 | 9 | 3 | -| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 1353 | 8 | 1299 | 29 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 137 | 1 | 90 | 10 | +| | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 1361 | 8 | 1307 | 30 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 143 | 1 | 90 | 10 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 23 | 1 | 22 | 1 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 205 | 0 | 21 | 2 | +| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 208 | 0 | 21 | 1 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 4 | 0 | 4 | 0 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 70 | 0 | 32 | 7 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 41 | 0 | 0 | 0 | @@ -129,7 +129,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 1 | 0 | 1 | 0 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 14 | 0 | 13 | 0 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 968 | 6 | 847 | 25 | -| transform | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 0 | 0 | 0 | 0 | +| | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [Kibana Localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | | | [Kibana Alerting](https://github.com/orgs/elastic/teams/kibana-alerting-services) | - | 239 | 1 | 230 | 18 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds UI Actions service to Kibana | 127 | 0 | 88 | 11 | @@ -150,7 +150,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the vislib visualizations. These are the classical area/line/bar, pie, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 26 | 0 | 25 | 1 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 57 | 0 | 51 | 5 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 275 | 13 | 257 | 15 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 304 | 13 | 286 | 16 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the visualize application which includes the listing page and the app frame, which will load the visualization's editor. | 24 | 0 | 23 | 1 | | watcher | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | xpackLegacy | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | @@ -159,6 +159,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| +| | [Owner missing] | Elastic APM trace data generator | 15 | 0 | 15 | 2 | | | [Owner missing] | elasticsearch datemath parser, used in kibana | 44 | 0 | 43 | 0 | | | [Owner missing] | - | 11 | 5 | 11 | 0 | | | [Owner missing] | Alerts components and hooks | 9 | 1 | 9 | 0 | @@ -166,20 +167,20 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | - | 14 | 0 | 14 | 0 | | | [Owner missing] | - | 11 | 0 | 11 | 0 | | | [Owner missing] | - | 2 | 0 | 2 | 0 | -| | [Owner missing] | - | 57 | 0 | 42 | 2 | +| | [Owner missing] | - | 66 | 0 | 46 | 1 | | | [Owner missing] | - | 109 | 3 | 107 | 18 | | | [Owner missing] | - | 13 | 0 | 7 | 0 | | | [Owner missing] | - | 258 | 7 | 231 | 4 | | | [Owner missing] | - | 1 | 0 | 1 | 0 | | | [Owner missing] | - | 25 | 0 | 12 | 1 | -| | [Owner missing] | - | 198 | 2 | 146 | 12 | +| | [Owner missing] | - | 205 | 2 | 153 | 14 | | | [Owner missing] | - | 20 | 0 | 16 | 0 | | | [Owner missing] | - | 2 | 0 | 2 | 2 | | | [Owner missing] | - | 18 | 0 | 18 | 2 | | | [Owner missing] | - | 30 | 0 | 5 | 37 | | | [Owner missing] | - | 467 | 9 | 378 | 0 | -| | [Owner missing] | - | 28 | 0 | 28 | 3 | -| | [Owner missing] | - | 42 | 0 | 42 | 9 | +| | [Owner missing] | - | 38 | 0 | 38 | 3 | +| | [Owner missing] | - | 44 | 0 | 44 | 9 | | | [Owner missing] | - | 1 | 0 | 1 | 0 | | | [Owner missing] | Just some helpers for kibana plugin devs. | 1 | 0 | 1 | 0 | | | [Owner missing] | - | 63 | 0 | 49 | 5 | @@ -203,7 +204,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | - | 18 | 1 | 18 | 0 | | | [Owner missing] | - | 2 | 0 | 2 | 0 | | | [Owner missing] | - | 200 | 5 | 177 | 9 | -| | [Owner missing] | - | 71 | 0 | 71 | 1 | +| | [Owner missing] | - | 78 | 0 | 78 | 1 | | | [Owner missing] | - | 29 | 1 | 10 | 1 | | | [Owner missing] | - | 31 | 1 | 21 | 0 | diff --git a/api_docs/saved_objects.json b/api_docs/saved_objects.json index b4e8c07d33ca2..af63ad120a8c0 100644 --- a/api_docs/saved_objects.json +++ b/api_docs/saved_objects.json @@ -2118,14 +2118,6 @@ "plugin": "discover", "path": "src/plugins/discover/public/application/apps/main/discover_main_route.tsx" }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/types.ts" - }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/types.ts" - }, { "plugin": "visualizations", "path": "src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts" diff --git a/api_docs/security_solution.json b/api_docs/security_solution.json index fe6a5cbb9858d..ebff5a94fbe2c 100644 --- a/api_docs/security_solution.json +++ b/api_docs/security_solution.json @@ -412,7 +412,9 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { enabled: boolean; signalsIndex: string; maxRuleImportExportSize: number; maxRuleImportPayloadBytes: number; maxTimelineImportExportSize: number; maxTimelineImportPayloadBytes: number; alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; alertIgnoreFields: string[]; enableExperimental: string[]; endpointResultListDefaultFirstPageIndex: number; endpointResultListDefaultPageSize: number; packagerTaskInterval: string; prebuiltRulesFromFileSystem: boolean; prebuiltRulesFromSavedObjects: boolean; }>" + "Readonly<{} & { enabled: boolean; signalsIndex: string; maxRuleImportExportSize: number; maxRuleImportPayloadBytes: number; maxTimelineImportExportSize: number; maxTimelineImportPayloadBytes: number; alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; alertIgnoreFields: string[]; enableExperimental: string[]; ruleExecutionLog: Readonly<{} & { underlyingClient: ", + "UnderlyingLogClient", + "; }>; endpointResultListDefaultFirstPageIndex: number; endpointResultListDefaultPageSize: number; packagerTaskInterval: string; prebuiltRulesFromFileSystem: boolean; prebuiltRulesFromSavedObjects: boolean; }>" ], "path": "x-pack/plugins/security_solution/server/client/client.ts", "deprecated": false, @@ -845,7 +847,9 @@ "label": "ConfigType", "description": [], "signature": [ - "{ readonly enabled: boolean; readonly signalsIndex: string; readonly maxRuleImportExportSize: number; readonly maxRuleImportPayloadBytes: number; readonly maxTimelineImportExportSize: number; readonly maxTimelineImportPayloadBytes: number; readonly alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; readonly alertIgnoreFields: string[]; readonly enableExperimental: string[]; readonly endpointResultListDefaultFirstPageIndex: number; readonly endpointResultListDefaultPageSize: number; readonly packagerTaskInterval: string; readonly prebuiltRulesFromFileSystem: boolean; readonly prebuiltRulesFromSavedObjects: boolean; }" + "{ readonly enabled: boolean; readonly signalsIndex: string; readonly maxRuleImportExportSize: number; readonly maxRuleImportPayloadBytes: number; readonly maxTimelineImportExportSize: number; readonly maxTimelineImportPayloadBytes: number; readonly alertMergeStrategy: \"allFields\" | \"missingFields\" | \"noFields\"; readonly alertIgnoreFields: string[]; readonly enableExperimental: string[]; readonly ruleExecutionLog: Readonly<{} & { underlyingClient: ", + "UnderlyingLogClient", + "; }>; readonly endpointResultListDefaultFirstPageIndex: number; readonly endpointResultListDefaultPageSize: number; readonly packagerTaskInterval: string; readonly prebuiltRulesFromFileSystem: boolean; readonly prebuiltRulesFromSavedObjects: boolean; }" ], "path": "x-pack/plugins/security_solution/server/config.ts", "deprecated": false, @@ -2437,12 +2441,15 @@ { "parentPluginId": "securitySolution", "id": "def-common.BrowserField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - "{ [key: string]: unknown; nested?: { path: string; } | undefined; } | undefined" + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined" ], "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", "deprecated": false @@ -2942,13 +2949,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/columns/index.tsx", @@ -7725,18 +7728,194 @@ }, { "parentPluginId": "securitySolution", - "id": "def-common.HostsRiskyHostsStrategyResponse", + "id": "def-common.HostsRiskScore", + "type": "Interface", + "tags": [], + "label": "HostsRiskScore", + "description": [], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScore.host", + "type": "Object", + "tags": [], + "label": "host", + "description": [], + "signature": [ + "{ name: string; }" + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScore.risk_score", + "type": "number", + "tags": [], + "label": "risk_score", + "description": [], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScore.risk", + "type": "string", + "tags": [], + "label": "risk", + "description": [], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreRequestOptions", + "type": "Interface", + "tags": [], + "label": "HostsRiskScoreRequestOptions", + "description": [], + "signature": [ + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.HostsRiskScoreRequestOptions", + "text": "HostsRiskScoreRequestOptions" + }, + " extends ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IEsSearchRequest", + "text": "IEsSearchRequest" + } + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreRequestOptions.defaultIndex", + "type": "Array", + "tags": [], + "label": "defaultIndex", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreRequestOptions.factoryQueryType", + "type": "CompoundType", + "tags": [], + "label": "factoryQueryType", + "description": [], + "signature": [ + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.HostsQueries", + "text": "HostsQueries" + }, + " | ", + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.HostsKpiQueries", + "text": "HostsKpiQueries" + }, + " | ", + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.UebaQueries", + "text": "UebaQueries" + }, + " | ", + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.NetworkQueries", + "text": "NetworkQueries" + }, + " | ", + { + "pluginId": "securitySolution", + "scope": "common", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-common.NetworkKpiQueries", + "text": "NetworkKpiQueries" + }, + " | ", + "CtiQueries", + " | \"matrixHistogram\" | \"matrixHistogramEntities\" | undefined" + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreRequestOptions.hostName", + "type": "string", + "tags": [], + "label": "hostName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreRequestOptions.timerange", + "type": "Object", + "tags": [], + "label": "timerange", + "description": [], + "signature": [ + { + "pluginId": "timelines", + "scope": "common", + "docId": "kibTimelinesPluginApi", + "section": "def-common.TimerangeInput", + "text": "TimerangeInput" + }, + " | undefined" + ], + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "securitySolution", + "id": "def-common.HostsRiskScoreStrategyResponse", "type": "Interface", "tags": [], - "label": "HostsRiskyHostsStrategyResponse", + "label": "HostsRiskScoreStrategyResponse", "description": [], "signature": [ { "pluginId": "securitySolution", "scope": "common", "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.HostsRiskyHostsStrategyResponse", - "text": "HostsRiskyHostsStrategyResponse" + "section": "def-common.HostsRiskScoreStrategyResponse", + "text": "HostsRiskScoreStrategyResponse" }, " extends ", { @@ -7748,12 +7927,12 @@ }, "" ], - "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts", + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", "deprecated": false, "children": [ { "parentPluginId": "securitySolution", - "id": "def-common.HostsRiskyHostsStrategyResponse.inspect", + "id": "def-common.HostsRiskScoreStrategyResponse.inspect", "type": "CompoundType", "tags": [], "label": "inspect", @@ -7768,7 +7947,7 @@ }, " | null | undefined" ], - "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts", + "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts", "deprecated": false } ], @@ -8937,18 +9116,14 @@ { "parentPluginId": "securitySolution", "id": "def-common.IndexField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", @@ -19263,13 +19438,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/columns/index.tsx", @@ -19832,26 +20003,6 @@ "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "securitySolution", - "id": "def-common.HostsRiskyHostsRequestOptions", - "type": "Type", - "tags": [], - "label": "HostsRiskyHostsRequestOptions", - "description": [], - "signature": [ - { - "pluginId": "securitySolution", - "scope": "common", - "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.RequestBasicOptions", - "text": "RequestBasicOptions" - } - ], - "path": "x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts", - "deprecated": false, - "initialIsOpen": false - }, { "parentPluginId": "securitySolution", "id": "def-common.HostTacticsSortField", @@ -21393,13 +21544,13 @@ "section": "def-common.HostsQueries", "text": "HostsQueries" }, - ".riskyHosts ? ", + ".hostsRiskScore ? ", { "pluginId": "securitySolution", "scope": "common", "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.RequestBasicOptions", - "text": "RequestBasicOptions" + "section": "def-common.HostsRiskScoreRequestOptions", + "text": "HostsRiskScoreRequestOptions" }, " : T extends ", { @@ -21883,13 +22034,13 @@ "section": "def-common.HostsQueries", "text": "HostsQueries" }, - ".riskyHosts ? ", + ".hostsRiskScore ? ", { "pluginId": "securitySolution", "scope": "common", "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.HostsRiskyHostsStrategyResponse", - "text": "HostsRiskyHostsStrategyResponse" + "section": "def-common.HostsRiskScoreStrategyResponse", + "text": "HostsRiskScoreStrategyResponse" }, " : T extends ", { diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index e3920a4a3685f..fec34843bbcdb 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -18,7 +18,7 @@ Contact [Security solution](https://github.com/orgs/elastic/teams/security-solut | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1353 | 8 | 1299 | 29 | +| 1361 | 8 | 1307 | 30 | ## Client diff --git a/api_docs/share.json b/api_docs/share.json index df192ba86bec3..992fcb9a0d43f 100644 --- a/api_docs/share.json +++ b/api_docs/share.json @@ -1912,7 +1912,15 @@ "section": "def-server.SerializableRecord", "text": "SerializableRecord" }, - ">): void; }" + ">): void; setAnonymousAccessServiceProvider: (provider: () => ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.AnonymousAccessServiceContract", + "text": "AnonymousAccessServiceContract" + }, + ") => void; }" ], "path": "src/plugins/share/public/plugin.ts", "deprecated": false, @@ -2224,6 +2232,107 @@ } ], "interfaces": [ + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessServiceContract", + "type": "Interface", + "tags": [], + "label": "AnonymousAccessServiceContract", + "description": [ + "\nThe contract that is used to check anonymous access for the purposes of sharing public links. The implementation is intended to be\nprovided by the security plugin." + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessServiceContract.getState", + "type": "Function", + "tags": [], + "label": "getState", + "description": [ + "\nThis function returns the current state of anonymous access." + ], + "signature": [ + "() => Promise<", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.AnonymousAccessState", + "text": "AnonymousAccessState" + }, + ">" + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessServiceContract.getCapabilities", + "type": "Function", + "tags": [], + "label": "getCapabilities", + "description": [ + "\nThis function returns the capabilities of the anonymous access user." + ], + "signature": [ + "() => Promise<", + "Capabilities", + ">" + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessState", + "type": "Interface", + "tags": [], + "label": "AnonymousAccessState", + "description": [ + "\nThe state of anonymous access." + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessState.isEnabled", + "type": "boolean", + "tags": [], + "label": "isEnabled", + "description": [ + "\nWhether anonymous access is enabled or not." + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false + }, + { + "parentPluginId": "share", + "id": "def-common.AnonymousAccessState.accessURLParameters", + "type": "CompoundType", + "tags": [], + "label": "accessURLParameters", + "description": [ + "\nIf anonymous access is enabled, this reflects what URL parameters need to be added to a Kibana link to make it publicly accessible.\nNote that if anonymous access is the only authentication method, this will be null." + ], + "signature": [ + "Record | null" + ], + "path": "src/plugins/share/common/anonymous_access/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "share", "id": "def-common.LocatorDefinition", diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 38fb5dc1a8485..61c0e26f24470 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -18,7 +18,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 137 | 1 | 90 | 10 | +| 143 | 1 | 90 | 10 | ## Client diff --git a/api_docs/spaces.json b/api_docs/spaces.json index e8195a0a47fc4..b391ca6ea0dbb 100644 --- a/api_docs/spaces.json +++ b/api_docs/spaces.json @@ -295,6 +295,45 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "spaces", + "id": "def-public.EmbeddableLegacyUrlConflictProps", + "type": "Interface", + "tags": [], + "label": "EmbeddableLegacyUrlConflictProps", + "description": [ + "\nProperties for the EmbeddableLegacyUrlConflict component." + ], + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "spaces", + "id": "def-public.EmbeddableLegacyUrlConflictProps.targetType", + "type": "string", + "tags": [], + "label": "targetType", + "description": [ + "\nThe target type of the legacy URL alias." + ], + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", + "deprecated": false + }, + { + "parentPluginId": "spaces", + "id": "def-public.EmbeddableLegacyUrlConflictProps.sourceId", + "type": "string", + "tags": [], + "label": "sourceId", + "description": [ + "\nThe source ID of the legacy URL alias." + ], + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "spaces", "id": "def-public.GetSpaceResult", @@ -359,7 +398,7 @@ "description": [ "\nProperties for the LegacyUrlConflict component." ], - "path": "x-pack/plugins/spaces/public/share_saved_objects_to_space/types.ts", + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", "deprecated": false, "children": [ { @@ -374,7 +413,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/spaces/public/share_saved_objects_to_space/types.ts", + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", "deprecated": false }, { @@ -386,7 +425,7 @@ "description": [ "\nThe ID of the object that is currently shown on the page." ], - "path": "x-pack/plugins/spaces/public/share_saved_objects_to_space/types.ts", + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", "deprecated": false }, { @@ -398,7 +437,7 @@ "description": [ "\nThe ID of the other object that the legacy URL alias points to." ], - "path": "x-pack/plugins/spaces/public/share_saved_objects_to_space/types.ts", + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", "deprecated": false }, { @@ -408,9 +447,9 @@ "tags": [], "label": "otherObjectPath", "description": [ - "\nThe path to use for the new URL, optionally including `search` and/or `hash` URL components." + "\n The path within your application to use for the new URL, optionally including `search` and/or `hash` URL components. Do not include\n `/app/my-app` or the current base path." ], - "path": "x-pack/plugins/spaces/public/share_saved_objects_to_space/types.ts", + "path": "x-pack/plugins/spaces/public/legacy_urls/types.ts", "deprecated": false } ], @@ -1305,12 +1344,12 @@ }, { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getLegacyUrlConflict", + "id": "def-public.SpacesApiUiComponent.getEmbeddableLegacyUrlConflict", "type": "Function", "tags": [], - "label": "getLegacyUrlConflict", + "label": "getEmbeddableLegacyUrlConflict", "description": [ - "\nDisplays a callout that needs to be used if a call to `SavedObjectsClient.resolve()` results in an `\"conflict\"` outcome, which\nindicates that the user has loaded the page which is associated directly with one object (A), *and* with a legacy URL that points to a\ndifferent object (B).\n\nIn this case, `SavedObjectsClient.resolve()` has returned object A. This component displays a warning callout to the user explaining\nthat there is a conflict, and it includes a button that will redirect the user to object B when clicked.\n\nConsumers need to determine the local path for the new URL on their own, based on the object ID that was used to call\n`SavedObjectsClient.resolve()` (A) and the `alias_target_id` value in the response (B). For example...\n\nA is `workpad-123` and B is `workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e`.\n\nFull legacy URL: `https://localhost:5601/app/canvas#/workpad/workpad-123/page/1`\n\nNew URL path: `#/workpad/workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e/page/1`" + "\nDisplays a callout that needs to be used if an embeddable component call to `SavedObjectsClient.resolve()` results in an `\"conflict\"`\noutcome, which indicates that the user has loaded an embeddable which is associated directly with one object (A), *and* with a legacy\nURL that points to a different object (B)." ], "signature": [ "(props: ", @@ -1318,8 +1357,8 @@ "pluginId": "spaces", "scope": "public", "docId": "kibSpacesPluginApi", - "section": "def-public.LegacyUrlConflictProps", - "text": "LegacyUrlConflictProps" + "section": "def-public.EmbeddableLegacyUrlConflictProps", + "text": "EmbeddableLegacyUrlConflictProps" }, ") => React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" ], @@ -1329,7 +1368,7 @@ "children": [ { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getLegacyUrlConflict.$1", + "id": "def-public.SpacesApiUiComponent.getEmbeddableLegacyUrlConflict.$1", "type": "Uncategorized", "tags": [], "label": "props", @@ -1344,12 +1383,12 @@ }, { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getSpaceAvatar", + "id": "def-public.SpacesApiUiComponent.getLegacyUrlConflict", "type": "Function", "tags": [], - "label": "getSpaceAvatar", + "label": "getLegacyUrlConflict", "description": [ - "\nDisplays an avatar for the given space." + "\nDisplays a callout that needs to be used if a call to `SavedObjectsClient.resolve()` results in an `\"conflict\"` outcome, which\nindicates that the user has loaded the page which is associated directly with one object (A), *and* with a legacy URL that points to a\ndifferent object (B).\n\nIn this case, `SavedObjectsClient.resolve()` has returned object A. This component displays a warning callout to the user explaining\nthat there is a conflict, and it includes a button that will redirect the user to object B when clicked.\n\nConsumers need to determine the local path for the new URL on their own, based on the object ID that was used to call\n`SavedObjectsClient.resolve()` (A) and the `alias_target_id` value in the response (B). For example...\n\nA is `workpad-123` and B is `workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e`.\n\nFull legacy URL: `https://localhost:5601/app/canvas#/workpad/workpad-123/page/1`\n\nNew URL path: `#/workpad/workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e/page/1`" ], "signature": [ "(props: ", @@ -1357,8 +1396,8 @@ "pluginId": "spaces", "scope": "public", "docId": "kibSpacesPluginApi", - "section": "def-public.SpaceAvatarProps", - "text": "SpaceAvatarProps" + "section": "def-public.LegacyUrlConflictProps", + "text": "LegacyUrlConflictProps" }, ") => React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" ], @@ -1368,7 +1407,7 @@ "children": [ { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getSpaceAvatar.$1", + "id": "def-public.SpacesApiUiComponent.getLegacyUrlConflict.$1", "type": "Uncategorized", "tags": [], "label": "props", @@ -1383,16 +1422,22 @@ }, { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getSavedObjectConflictMessage", + "id": "def-public.SpacesApiUiComponent.getSpaceAvatar", "type": "Function", "tags": [], - "label": "getSavedObjectConflictMessage", + "label": "getSpaceAvatar", "description": [ - "\nDisplays a saved object conflict message that directs user to disable legacy URL alias" + "\nDisplays an avatar for the given space." ], "signature": [ "(props: ", - "SavedObjectConflictMessageProps", + { + "pluginId": "spaces", + "scope": "public", + "docId": "kibSpacesPluginApi", + "section": "def-public.SpaceAvatarProps", + "text": "SpaceAvatarProps" + }, ") => React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)>" ], "path": "x-pack/plugins/spaces/public/ui_api/types.ts", @@ -1401,7 +1446,7 @@ "children": [ { "parentPluginId": "spaces", - "id": "def-public.SpacesApiUiComponent.getSavedObjectConflictMessage.$1", + "id": "def-public.SpacesApiUiComponent.getSpaceAvatar.$1", "type": "Uncategorized", "tags": [], "label": "props", diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 12e803604cede..9f4bf1d79346a 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -18,7 +18,7 @@ Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-securit | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 205 | 0 | 21 | 2 | +| 208 | 0 | 21 | 1 | ## Client diff --git a/api_docs/timelines.json b/api_docs/timelines.json index eb31eb6849a86..416f623520394 100644 --- a/api_docs/timelines.json +++ b/api_docs/timelines.json @@ -1657,13 +1657,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; })[]; id: string; title: string; filters?: ", { "pluginId": "@kbn/es-query", @@ -1709,13 +1705,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; })[]; savedObjectId: string | null; unit?: ((n: number) => React.ReactNode) | undefined; dataProviders: ", { "pluginId": "timelines", @@ -1732,15 +1724,15 @@ "section": "def-common.RowRendererId", "text": "RowRendererId" }, - "[]; expandedDetail: ", + "[]; expandedDetail: Partial>; footerText?: React.ReactNode; graphEventId?: string | undefined; kqlQuery: { filterQuery: ", { "pluginId": "timelines", "scope": "common", @@ -5582,12 +5574,15 @@ { "parentPluginId": "timelines", "id": "def-common.BrowserField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - "{ [key: string]: unknown; nested?: { path: string; } | undefined; } | undefined" + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", + " | undefined" ], "path": "x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts", "deprecated": false @@ -6153,13 +6148,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/columns/index.tsx", @@ -8418,18 +8409,14 @@ { "parentPluginId": "timelines", "id": "def-common.IndexField.subType", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "subType", "description": [], "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined" ], "path": "x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts", @@ -11273,14 +11260,15 @@ "label": "expandedDetail", "description": [], "signature": [ + "Partial> | undefined" ], "path": "x-pack/plugins/timelines/common/types/timeline/store.ts", "deprecated": false @@ -12716,13 +12704,9 @@ "text": "ColumnHeaderType" }, "; description?: string | undefined; example?: string | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.IFieldSubType", - "text": "IFieldSubType" - }, + "IFieldSubTypeMultiOptional", + " | ", + "IFieldSubTypeNestedOptional", " | undefined; type?: string | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/columns/index.tsx", @@ -14383,17 +14367,9 @@ "label": "TimelineExpandedDetail", "description": [], "signature": [ - "{ query?: Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", - "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; graph?: Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", - "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; notes?: Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", - "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; pinned?: Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", - "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; eql?: Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", + "{ [x: string]: { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; }" + " | undefined; } | undefined; } | Partial> | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; } | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/index.ts", "deprecated": false, @@ -14407,9 +14383,9 @@ "label": "TimelineExpandedDetailType", "description": [], "signature": [ - "Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", + "{ panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", "Ecs", - " | undefined; } | undefined; } | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; }" + " | undefined; } | undefined; } | Partial> | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; } | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/index.ts", "deprecated": false, @@ -14423,9 +14399,9 @@ "label": "TimelineExpandedEventType", "description": [], "signature": [ - "Record | { panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", + "{ panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", "Ecs", - " | undefined; } | undefined; }" + " | undefined; } | undefined; } | Partial>" ], "path": "x-pack/plugins/timelines/common/types/timeline/index.ts", "deprecated": false, @@ -14439,7 +14415,7 @@ "label": "TimelineExpandedHostType", "description": [], "signature": [ - "Record | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; }" + "Partial> | { panelView?: \"hostDetail\" | undefined; params?: { hostName: string; } | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/index.ts", "deprecated": false, @@ -14453,7 +14429,7 @@ "label": "TimelineExpandedNetworkType", "description": [], "signature": [ - "Record | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; }" + "Partial> | { panelView?: \"networkDetail\" | undefined; params?: { ip: string; flowTarget: FlowTarget; } | undefined; }" ], "path": "x-pack/plugins/timelines/common/types/timeline/index.ts", "deprecated": false, @@ -14894,7 +14870,9 @@ "label": "ToggleDetailPanel", "description": [], "signature": [ - "(Record & { tabType?: ", + "({ panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", + "Ecs", + " | undefined; } | undefined; } & { tabType?: ", { "pluginId": "timelines", "scope": "common", @@ -14902,9 +14880,7 @@ "section": "def-common.TimelineTabs", "text": "TimelineTabs" }, - " | undefined; timelineId: string; }) | ({ panelView?: \"eventDetail\" | undefined; params?: { eventId: string; indexName: string; ecsData?: ", - "Ecs", - " | undefined; } | undefined; } & { tabType?: ", + " | undefined; timelineId: string; }) | (Partial> & { tabType?: ", { "pluginId": "timelines", "scope": "common", diff --git a/api_docs/transform.json b/api_docs/transform.json new file mode 100644 index 0000000000000..cbf3b9dbac343 --- /dev/null +++ b/api_docs/transform.json @@ -0,0 +1,101 @@ +{ + "id": "transform", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "transform", + "id": "def-public.getTransformHealthRuleType", + "type": "Function", + "tags": [], + "label": "getTransformHealthRuleType", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "triggersActionsUi", + "scope": "public", + "docId": "kibTriggersActionsUiPluginApi", + "section": "def-public.AlertTypeModel", + "text": "AlertTypeModel" + }, + "<", + "TransformHealthRuleParams", + ">" + ], + "path": "x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "transform", + "id": "def-server.registerTransformHealthRuleType", + "type": "Function", + "tags": [], + "label": "registerTransformHealthRuleType", + "description": [], + "signature": [ + "(params: RegisterParams) => void" + ], + "path": "x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "transform", + "id": "def-server.registerTransformHealthRuleType.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "RegisterParams" + ], + "path": "x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "transform", + "id": "def-common.TRANSFORM_RULE_TYPE", + "type": "Object", + "tags": [], + "label": "TRANSFORM_RULE_TYPE", + "description": [], + "signature": [ + "{ readonly TRANSFORM_HEALTH: \"transform_health\"; }" + ], + "path": "x-pack/plugins/transform/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + } + ] + } +} \ No newline at end of file diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx new file mode 100644 index 0000000000000..21541177b3cec --- /dev/null +++ b/api_docs/transform.mdx @@ -0,0 +1,37 @@ +--- +id: kibTransformPluginApi +slug: /kibana-dev-docs/api/transform +title: "transform" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the transform plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import transformObj from './transform.json'; + +This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. + +Contact [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 4 | 0 | 4 | 1 | + +## Client + +### Functions + + +## Server + +### Functions + + +## Common + +### Objects + + diff --git a/api_docs/vis_default_editor.json b/api_docs/vis_default_editor.json index 883d846e67bb8..619c3734e9517 100644 --- a/api_docs/vis_default_editor.json +++ b/api_docs/vis_default_editor.json @@ -943,9 +943,9 @@ "(paramName: T, value: ", { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemaParams", + "section": "def-common.ColorSchemaParams", "text": "ColorSchemaParams" }, "[T]) => void" @@ -977,9 +977,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.ColorSchemaParams", + "section": "def-common.ColorSchemaParams", "text": "ColorSchemaParams" }, "[T]" diff --git a/api_docs/vis_type_vislib.json b/api_docs/vis_type_vislib.json index f7bac3f7e3e9e..3b5d895ac4c83 100644 --- a/api_docs/vis_type_vislib.json +++ b/api_docs/vis_type_vislib.json @@ -107,9 +107,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.Labels", + "section": "def-common.Labels", "text": "Labels" } ], diff --git a/api_docs/vis_type_xy.json b/api_docs/vis_type_xy.json index 92df25763766e..0cb9fd390d188 100644 --- a/api_docs/vis_type_xy.json +++ b/api_docs/vis_type_xy.json @@ -141,9 +141,9 @@ "signature": [ { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.Labels", + "section": "def-common.Labels", "text": "Labels" } ], @@ -231,9 +231,9 @@ "Partial<", { "pluginId": "charts", - "scope": "public", + "scope": "common", "docId": "kibChartsPluginApi", - "section": "def-public.Style", + "section": "def-common.Style", "text": "Style" }, "> | undefined" diff --git a/api_docs/visualizations.json b/api_docs/visualizations.json index e93eec8a07ee8..d131d522b3515 100644 --- a/api_docs/visualizations.json +++ b/api_docs/visualizations.json @@ -1140,6 +1140,37 @@ } ], "functions": [ + { + "parentPluginId": "visualizations", + "id": "def-public.getFullPath", + "type": "Function", + "tags": [], + "label": "getFullPath", + "description": [], + "signature": [ + "(id: string) => string" + ], + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.getFullPath.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "visualizations", "id": "def-public.getVisSchemas", @@ -1360,6 +1391,37 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "visualizations", + "id": "def-public.urlFor", + "type": "Function", + "tags": [], + "label": "urlFor", + "description": [], + "signature": [ + "(id: string) => string" + ], + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.urlFor.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "visualizations", "id": "def-public.VisualizationContainer", @@ -1494,6 +1556,98 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions", + "type": "Interface", + "tags": [], + "label": "GetVisOptions", + "description": [], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.searchSource", + "type": "CompoundType", + "tags": [], + "label": "searchSource", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.migrationVersion", + "type": "Object", + "tags": [], + "label": "migrationVersion", + "description": [], + "signature": [ + "SavedObjectsMigrationVersion", + " | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.savedSearchId", + "type": "string", + "tags": [], + "label": "savedSearchId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.GetVisOptions.indexPattern", + "type": "string", + "tags": [], + "label": "indexPattern", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "visualizations", "id": "def-public.HistogramParams", @@ -1640,6 +1794,19 @@ ], "path": "src/plugins/visualizations/public/types.ts", "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.ISavedVis.sharingSavedObjectProps", + "type": "Object", + "tags": [], + "label": "sharingSavedObjectProps", + "description": [], + "signature": [ + "{ outcome?: \"conflict\" | \"exactMatch\" | \"aliasMatch\" | undefined; aliasTargetId?: string | undefined; errorJSON?: string | undefined; } | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false } ], "initialIsOpen": false @@ -2531,14 +2698,6 @@ "text": "VisSavedObject" }, " extends ", - { - "pluginId": "savedObjects", - "scope": "public", - "docId": "kibSavedObjectsPluginApi", - "section": "def-public.SavedObject", - "text": "SavedObject" - }, - ",", { "pluginId": "visualizations", "scope": "public", @@ -2549,7 +2708,119 @@ ], "path": "src/plugins/visualizations/public/types.ts", "deprecated": false, - "children": [], + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.lastSavedTitle", + "type": "string", + "tags": [], + "label": "lastSavedTitle", + "description": [], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.getEsType", + "type": "Function", + "tags": [], + "label": "getEsType", + "description": [], + "signature": [ + "() => string" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.getDisplayName", + "type": "Function", + "tags": [], + "label": "getDisplayName", + "description": [], + "signature": [ + "(() => string) | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.displayName", + "type": "string", + "tags": [], + "label": "displayName", + "description": [], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.migrationVersion", + "type": "Object", + "tags": [], + "label": "migrationVersion", + "description": [], + "signature": [ + "SavedObjectsMigrationVersion", + " | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.searchSource", + "type": "Object", + "tags": [], + "label": "searchSource", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSource", + "text": "SearchSource" + }, + ", \"create\" | \"history\" | \"setPreferredSearchStrategyId\" | \"setField\" | \"removeField\" | \"setFields\" | \"getId\" | \"getFields\" | \"getField\" | \"getOwnField\" | \"createCopy\" | \"createChild\" | \"setParent\" | \"getParent\" | \"fetch$\" | \"fetch\" | \"onRequestStart\" | \"getSearchRequestBody\" | \"destroy\" | \"getSerializedFields\" | \"serialize\"> | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.version", + "type": "string", + "tags": [], + "label": "version", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisSavedObject.tags", + "type": "Array", + "tags": [], + "label": "tags", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "src/plugins/visualizations/public/types.ts", + "deprecated": false + } + ], "initialIsOpen": false }, { @@ -4788,8 +5059,8 @@ "pluginId": "visualizations", "scope": "public", "docId": "kibVisualizationsPluginApi", - "section": "def-public.ISavedVis", - "text": "ISavedVis" + "section": "def-public.VisSavedObject", + "text": "VisSavedObject" }, ") => ", { @@ -4825,11 +5096,11 @@ "pluginId": "visualizations", "scope": "public", "docId": "kibVisualizationsPluginApi", - "section": "def-public.ISavedVis", - "text": "ISavedVis" + "section": "def-public.VisSavedObject", + "text": "VisSavedObject" } ], - "path": "src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts", + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", "deprecated": false } ] @@ -4896,7 +5167,7 @@ }, ">" ], - "path": "src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts", + "path": "src/plugins/visualizations/public/utils/saved_visualize_utils.ts", "deprecated": false } ] @@ -4932,6 +5203,193 @@ } ] }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.getSavedVisualization", + "type": "Function", + "tags": [], + "label": "getSavedVisualization", + "description": [], + "signature": [ + "(opts?: string | ", + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.GetVisOptions", + "text": "GetVisOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.VisSavedObject", + "text": "VisSavedObject" + }, + ">" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.getSavedVisualization.$1", + "type": "CompoundType", + "tags": [], + "label": "opts", + "description": [], + "signature": [ + "string | ", + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.GetVisOptions", + "text": "GetVisOptions" + }, + " | undefined" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.saveVisualization", + "type": "Function", + "tags": [], + "label": "saveVisualization", + "description": [], + "signature": [ + "(savedVis: ", + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.VisSavedObject", + "text": "VisSavedObject" + }, + ", saveOptions: ", + "SaveVisOptions", + ") => Promise" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.saveVisualization.$1", + "type": "Object", + "tags": [], + "label": "savedVis", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.VisSavedObject", + "text": "VisSavedObject" + } + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.saveVisualization.$2", + "type": "Object", + "tags": [], + "label": "saveOptions", + "description": [], + "signature": [ + "SaveVisOptions" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.findListItems", + "type": "Function", + "tags": [], + "label": "findListItems", + "description": [], + "signature": [ + "(searchTerm: string, listingLimit: number, references?: ", + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + "[] | undefined) => Promise<{ hits: Record[]; total: number; }>" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.findListItems.$1", + "type": "string", + "tags": [], + "label": "searchTerm", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.findListItems.$2", + "type": "number", + "tags": [], + "label": "listingLimit", + "description": [], + "signature": [ + "number" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationsStart.findListItems.$3", + "type": "Array", + "tags": [], + "label": "references", + "description": [], + "signature": [ + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreSavedObjectsPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + "[] | undefined" + ], + "path": "src/plugins/visualizations/public/plugin.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, { "parentPluginId": "visualizations", "id": "def-public.VisualizationsStart.__LEGACY", @@ -4964,17 +5422,7 @@ "section": "def-public.VisualizeInput", "text": "VisualizeInput" }, - "> & { id: string; }, savedVisualizationsLoader?: (", - { - "pluginId": "savedObjects", - "scope": "public", - "docId": "kibSavedObjectsPluginApi", - "section": "def-public.SavedObjectLoader", - "text": "SavedObjectLoader" - }, - " & { findListItems: (search: string, sizeOrOptions?: number | ", - "FindListItemsOptions", - " | undefined) => any; }) | undefined, attributeService?: ", + "> & { id: string; }, attributeService?: ", { "pluginId": "embeddable", "scope": "public", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index a9501b59a1a55..5253bcdcd57e0 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -18,7 +18,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 275 | 13 | 257 | 15 | +| 304 | 13 | 286 | 16 | ## Client diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.json b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.json deleted file mode 100644 index c7b43d9436cb9..0000000000000 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "id": "pluginA.foo", - "client": { - "classes": [], - "functions": [ - { - "parentPluginId": "pluginA", - "id": "def-public.doTheFooFnThing", - "type": "Function", - "tags": [], - "label": "doTheFooFnThing", - "description": [], - "signature": [ - "() => void" - ], - "path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts", - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - } - ], - "interfaces": [], - "enums": [], - "misc": [ - { - "parentPluginId": "pluginA", - "id": "def-public.FooType", - "type": "Type", - "tags": [], - "label": "FooType", - "description": [], - "signature": [ - "() => \"foo\"" - ], - "path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts", - "deprecated": false, - "returnComment": [], - "children": [], - "initialIsOpen": false - } - ], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [ - { - "parentPluginId": "pluginA", - "id": "def-common.commonFoo", - "type": "string", - "tags": [], - "label": "commonFoo", - "description": [], - "signature": [ - "\"COMMON VAR!\"" - ], - "path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts", - "deprecated": false, - "initialIsOpen": false - } - ], - "objects": [] - } -} \ No newline at end of file diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.mdx deleted file mode 100644 index 1fd371b585ce7..0000000000000 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.foo.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -id: kibPluginAFooPluginApi -slug: /kibana-dev-docs/pluginA.fooPluginApi -title: pluginA.foo -image: https://source.unsplash.com/400x175/?github -summary: API docs for the pluginA.foo plugin -date: 2020-11-16 -tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA.foo'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. ---- -import pluginA.fooObj from './plugin_a.foo.json'; - - - -Contact Kibana Core for questions regarding this plugin. - -**Code health stats** - -| Public API count | Any count | Items lacking comments | Missing exports | -|-------------------|-----------|------------------------|-----------------| -| 3 | 0 | 0 | 0 | - -## Client - -### Functions - - -### Consts, variables and types - - -## Common - -### Consts, variables and types - - From 6cb91c472dfbc9ef6c38258407bc8a4b2dca6540 Mon Sep 17 00:00:00 2001 From: James Rucker Date: Mon, 11 Oct 2021 17:08:49 -0700 Subject: [PATCH 28/73] [Enterprise Search] Warn about Kibana access when adding single user role mappings (#114567) * Warn about Kibana access when adding single user role mappings to Enterprise Search * i18n and sentence case for the Kibana access warning title --- .../components/role_mappings/user.tsx | 1 + .../shared/role_mapping/constants.ts | 22 ++++++ .../role_mapping/user_added_info.test.tsx | 67 +++++++++++++++++++ .../shared/role_mapping/user_added_info.tsx | 29 +++++++- .../public/applications/shared/types.ts | 1 + .../views/role_mappings/user.tsx | 1 + 6 files changed, 118 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/user.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/user.tsx index 57f08c22220f7..9e041dd83a293 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/user.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/user.tsx @@ -69,6 +69,7 @@ export const User: React.FC = () => { username={singleUserRoleMapping.elasticsearchUser.username} email={singleUserRoleMapping.elasticsearchUser.email as string} roleType={singleUserRoleMapping.roleMapping.roleType} + showKibanaAccessWarning={!singleUserRoleMapping.hasEnterpriseSearchRole} /> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts index 25a1e084a3a60..d2229b428932f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts @@ -448,3 +448,25 @@ export const SMTP_CALLOUT_LABEL = i18n.translate( export const SMTP_LINK_LABEL = i18n.translate('xpack.enterpriseSearch.roleMapping.smtpLinkLabel', { defaultMessage: 'SMTP configuration is provided', }); + +export const KIBANA_ACCESS_WARNING_TITLE = i18n.translate( + 'xpack.enterpriseSearch.roleMapping.kibanaAccessWarningTitle', + { + defaultMessage: 'Kibana access warning', + } +); + +export const KIBANA_ACCESS_WARNING_ERROR_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.roleMapping.kibanaAccessWarningErrorMessage', + { + defaultMessage: + 'This Elasticsearch user does not have an Enterprise Search role in Elasticsearch. They may not have access to Kibana.', + } +); + +export const KIBANA_ACCESS_WARNING_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.roleMapping.kibanaAccessWarningDescription', + { + defaultMessage: 'Consider giving them the "enterprise-search-user" role.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.test.tsx index 57200b389591d..05ccafbe3e38f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.test.tsx @@ -16,6 +16,7 @@ describe('UserAddedInfo', () => { username: 'user1', email: 'test@test.com', roleType: 'user', + showKibanaAccessWarning: false, }; it('renders with email', () => { @@ -117,4 +118,70 @@ describe('UserAddedInfo', () => { `); }); + + it('renders with the Kibana access warning', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchInlineSnapshot(` + + + + This Elasticsearch user does not have an Enterprise Search role in Elasticsearch. They may not have access to Kibana. + + + + Consider giving them the "enterprise-search-user" role. + + + + + + Username + + + + user1 + + + + + Email + + + + test@test.com + + + + + Role + + + + user + + + + `); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.tsx index 37804414a94a9..71fb3d76295f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_added_info.tsx @@ -7,22 +7,45 @@ import React from 'react'; -import { EuiSpacer, EuiText, EuiTextColor } from '@elastic/eui'; +import { EuiCallOut, EuiSpacer, EuiText, EuiTextColor } from '@elastic/eui'; import { USERNAME_LABEL, EMAIL_LABEL } from '../constants'; -import { ROLE_LABEL } from './constants'; +import { + KIBANA_ACCESS_WARNING_TITLE, + KIBANA_ACCESS_WARNING_DESCRIPTION, + KIBANA_ACCESS_WARNING_ERROR_MESSAGE, + ROLE_LABEL, +} from './constants'; interface Props { username: string; email: string; roleType: string; + showKibanaAccessWarning: boolean; } +const kibanaAccessWarning = ( + <> + + {KIBANA_ACCESS_WARNING_ERROR_MESSAGE} + + {KIBANA_ACCESS_WARNING_DESCRIPTION} + + + +); + const noItemsPlaceholder = ; -export const UserAddedInfo: React.FC = ({ username, email, roleType }) => ( +export const UserAddedInfo: React.FC = ({ + username, + email, + roleType, + showKibanaAccessWarning, +}) => ( <> + {showKibanaAccessWarning && kibanaAccessWarning} {USERNAME_LABEL} diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts index 4743e808cc6ea..51a83cb15cca5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts @@ -55,4 +55,5 @@ export interface SingleUserRoleMapping { invitation: Invitation | null; elasticsearchUser: ElasticsearchUser; roleMapping: T; + hasEnterpriseSearchRole?: boolean; } diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/user.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/user.tsx index 33785b4a4ce0e..e6244a0c7b2e0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/user.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/user.tsx @@ -66,6 +66,7 @@ export const User: React.FC = () => { username={singleUserRoleMapping.elasticsearchUser.username} email={singleUserRoleMapping.elasticsearchUser.email as string} roleType={singleUserRoleMapping.roleMapping.roleType} + showKibanaAccessWarning={!singleUserRoleMapping.hasEnterpriseSearchRole} /> ); From 44c9611bd9256f069b7dddac4d95c90adcace628 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 11 Oct 2021 17:49:21 -0700 Subject: [PATCH 29/73] [8.0] Remove support for configuring csp.rules (#114379) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../kibana-plugin-core-server.cspconfig.md | 1 - ...bana-plugin-core-server.cspconfig.rules.md | 11 -- ...core-server.icspconfig.disableembedding.md | 2 +- .../kibana-plugin-core-server.icspconfig.md | 3 +- ...ana-plugin-core-server.icspconfig.rules.md | 13 -- docs/migration/migrate_8_0.asciidoc | 6 + docs/setup/settings.asciidoc | 10 +- .../deprecation/core_deprecations.test.ts | 96 ------------ .../config/deprecation/core_deprecations.ts | 59 +------ src/core/server/csp/config.test.ts | 144 ++--------------- src/core/server/csp/config.ts | 41 ----- src/core/server/csp/csp_config.test.ts | 62 ++------ src/core/server/csp/csp_config.ts | 14 +- src/core/server/csp/csp_directives.test.ts | 147 +----------------- src/core/server/csp/csp_directives.ts | 28 +--- .../http_resources_service.test.ts | 8 +- src/core/server/server.api.md | 3 - .../resources/base/bin/kibana-docker | 1 - .../collectors/csp/csp_collector.test.ts | 8 +- 19 files changed, 54 insertions(+), 603 deletions(-) delete mode 100644 docs/development/core/server/kibana-plugin-core-server.cspconfig.rules.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.icspconfig.rules.md diff --git a/docs/development/core/server/kibana-plugin-core-server.cspconfig.md b/docs/development/core/server/kibana-plugin-core-server.cspconfig.md index 0337a1f4d3301..46f24dfda6739 100644 --- a/docs/development/core/server/kibana-plugin-core-server.cspconfig.md +++ b/docs/development/core/server/kibana-plugin-core-server.cspconfig.md @@ -24,7 +24,6 @@ The constructor for this class is marked as internal. Third-party code should no | [DEFAULT](./kibana-plugin-core-server.cspconfig.default.md) | static | CspConfig | | | [disableEmbedding](./kibana-plugin-core-server.cspconfig.disableembedding.md) | | boolean | | | [header](./kibana-plugin-core-server.cspconfig.header.md) | | string | | -| [rules](./kibana-plugin-core-server.cspconfig.rules.md) | | string[] | | | [strict](./kibana-plugin-core-server.cspconfig.strict.md) | | boolean | | | [warnLegacyBrowsers](./kibana-plugin-core-server.cspconfig.warnlegacybrowsers.md) | | boolean | | diff --git a/docs/development/core/server/kibana-plugin-core-server.cspconfig.rules.md b/docs/development/core/server/kibana-plugin-core-server.cspconfig.rules.md deleted file mode 100644 index 2bc73345fe0d0..0000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.cspconfig.rules.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CspConfig](./kibana-plugin-core-server.cspconfig.md) > [rules](./kibana-plugin-core-server.cspconfig.rules.md) - -## CspConfig.rules property - -Signature: - -```typescript -readonly rules: string[]; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.icspconfig.disableembedding.md b/docs/development/core/server/kibana-plugin-core-server.icspconfig.disableembedding.md index 2cfd680459fbc..42b177c348afe 100644 --- a/docs/development/core/server/kibana-plugin-core-server.icspconfig.disableembedding.md +++ b/docs/development/core/server/kibana-plugin-core-server.icspconfig.disableembedding.md @@ -4,7 +4,7 @@ ## ICspConfig.disableEmbedding property -Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled \*and\* no custom rules have been defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. +Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.icspconfig.md b/docs/development/core/server/kibana-plugin-core-server.icspconfig.md index ee49950df076c..9da31cdc11e36 100644 --- a/docs/development/core/server/kibana-plugin-core-server.icspconfig.md +++ b/docs/development/core/server/kibana-plugin-core-server.icspconfig.md @@ -16,9 +16,8 @@ export interface ICspConfig | Property | Type | Description | | --- | --- | --- | -| [disableEmbedding](./kibana-plugin-core-server.icspconfig.disableembedding.md) | boolean | Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled \*and\* no custom rules have been defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. | +| [disableEmbedding](./kibana-plugin-core-server.icspconfig.disableembedding.md) | boolean | Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. | | [header](./kibana-plugin-core-server.icspconfig.header.md) | string | The CSP rules in a formatted directives string for use in a Content-Security-Policy header. | -| [rules](./kibana-plugin-core-server.icspconfig.rules.md) | string[] | The CSP rules used for Kibana. | | [strict](./kibana-plugin-core-server.icspconfig.strict.md) | boolean | Specify whether browsers that do not support CSP should be able to use Kibana. Use true to block and false to allow. | | [warnLegacyBrowsers](./kibana-plugin-core-server.icspconfig.warnlegacybrowsers.md) | boolean | Specify whether users with legacy browsers should be warned about their lack of Kibana security compliance. | diff --git a/docs/development/core/server/kibana-plugin-core-server.icspconfig.rules.md b/docs/development/core/server/kibana-plugin-core-server.icspconfig.rules.md deleted file mode 100644 index 808eefc30b64c..0000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.icspconfig.rules.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ICspConfig](./kibana-plugin-core-server.icspconfig.md) > [rules](./kibana-plugin-core-server.icspconfig.rules.md) - -## ICspConfig.rules property - -The CSP rules used for Kibana. - -Signature: - -```typescript -readonly rules: string[]; -``` diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc index 60a65580501a6..dc6754fba1ffc 100644 --- a/docs/migration/migrate_8_0.asciidoc +++ b/docs/migration/migrate_8_0.asciidoc @@ -48,6 +48,12 @@ for example, `logstash-*`. *Impact:* To allow Kibana to function for these legacy browsers, set `csp.strict: false`. Since this is about enforcing a security protocol, we *strongly discourage* disabling `csp.strict` unless it is critical that you support Internet Explorer 11. +[float] +==== Configuring content security policy rules is no longer supported +*Details:* Configuring `csp.rules` is removed in favor of per-directive specific configuration. Configuring the default `csp.script_src`, `csp.workers_src` and `csp.style_src` values is not required. + +*Impact:* Configure per-directive sources instead. See https://github.com/elastic/kibana/pull/102059 for more details. + [float] ==== Default logging timezone is now the system's timezone *Details:* In prior releases the timezone used in logs defaulted to UTC. We now use the host machine's timezone by default. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 9c3d4fc29f137..48bf5fe2cd7b3 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -26,13 +26,6 @@ Toggling this causes the server to regenerate assets on the next startup, which may cause a delay before pages start being served. Set to `false` to disable Console. *Default: `true`* -| `csp.rules:` - | deprecated:[7.14.0,"In 8.0 and later, this setting will no longer be supported."] -A https://w3c.github.io/webappsec-csp/[Content Security Policy] template -that disables certain unnecessary and potentially insecure capabilities in -the browser. It is strongly recommended that you keep the default CSP rules -that ship with {kib}. - | `csp.script_src:` | Add sources for the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src[Content Security Policy `script-src` directive]. @@ -502,8 +495,7 @@ To disable, set to `null`. *Default:* `null` | Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy[`Content-Security-Policy`] and https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options[`X-Frame-Options`] headers are configured to disable embedding {kib} in other webpages using iframes. When set to `true`, secure headers are used to disable embedding, which adds the `frame-ancestors: -'self'` directive to the `Content-Security-Policy` response header (if you are using the default CSP rules), and adds the `X-Frame-Options: -SAMEORIGIN` response header. *Default:* `false` +'self'` directive to the `Content-Security-Policy` response header and adds the `X-Frame-Options: SAMEORIGIN` response header. *Default:* `false` | `server.customResponseHeaders:` {ess-icon} | Header names and values to diff --git a/src/core/server/config/deprecation/core_deprecations.test.ts b/src/core/server/config/deprecation/core_deprecations.test.ts index 95e23561a9378..e08f2216f5cbe 100644 --- a/src/core/server/config/deprecation/core_deprecations.test.ts +++ b/src/core/server/config/deprecation/core_deprecations.test.ts @@ -83,100 +83,4 @@ describe('core deprecations', () => { expect(messages).toHaveLength(0); }); }); - - describe('cspRulesDeprecation', () => { - describe('with nonce source', () => { - it('logs a warning', () => { - const settings = { - csp: { - rules: [`script-src 'self' 'nonce-{nonce}'`], - }, - }; - const { messages } = applyCoreDeprecations(settings); - expect(messages).toMatchInlineSnapshot(` - Array [ - "csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in script-src", - ] - `); - }); - - it('replaces a nonce', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'nonce-{nonce}'`] } }).migrated.csp - .rules - ).toEqual([`script-src 'self'`]); - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'unsafe-eval' 'nonce-{nonce}'`] } }) - .migrated.csp.rules - ).toEqual([`script-src 'unsafe-eval' 'self'`]); - }); - - it('removes a quoted nonce', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'self' 'nonce-{nonce}'`] } }).migrated - .csp.rules - ).toEqual([`script-src 'self'`]); - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'nonce-{nonce}' 'self'`] } }).migrated - .csp.rules - ).toEqual([`script-src 'self'`]); - }); - - it('removes a non-quoted nonce', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'self' nonce-{nonce}`] } }).migrated - .csp.rules - ).toEqual([`script-src 'self'`]); - expect( - applyCoreDeprecations({ csp: { rules: [`script-src nonce-{nonce} 'self'`] } }).migrated - .csp.rules - ).toEqual([`script-src 'self'`]); - }); - - it('removes a strange nonce', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'self' blah-{nonce}-wow`] } }).migrated - .csp.rules - ).toEqual([`script-src 'self'`]); - }); - - it('removes multiple nonces', () => { - expect( - applyCoreDeprecations({ - csp: { - rules: [ - `script-src 'nonce-{nonce}' 'self' blah-{nonce}-wow`, - `style-src 'nonce-{nonce}' 'self'`, - ], - }, - }).migrated.csp.rules - ).toEqual([`script-src 'self'`, `style-src 'self'`]); - }); - }); - - describe('without self source', () => { - it('logs a warning', () => { - const { messages } = applyCoreDeprecations({ - csp: { rules: [`script-src 'unsafe-eval'`] }, - }); - expect(messages).toMatchInlineSnapshot(` - Array [ - "csp.rules must contain the 'self' source. Automatically adding to script-src.", - ] - `); - }); - - it('adds self', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`script-src 'unsafe-eval'`] } }).migrated.csp.rules - ).toEqual([`script-src 'unsafe-eval' 'self'`]); - }); - }); - - it('does not add self to other policies', () => { - expect( - applyCoreDeprecations({ csp: { rules: [`worker-src blob:`] } }).migrated.csp.rules - ).toEqual([`worker-src blob:`]); - }); - }); }); diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index 4e5f711fe9f3a..5adbb338b42e4 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -45,64 +45,7 @@ const rewriteCorsSettings: ConfigDeprecation = (settings, fromPath, addDeprecati } }; -const cspRulesDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => { - const NONCE_STRING = `{nonce}`; - // Policies that should include the 'self' source - const SELF_POLICIES = Object.freeze(['script-src', 'style-src']); - const SELF_STRING = `'self'`; - - const rules: string[] = settings.csp?.rules; - if (rules) { - const parsed = new Map( - rules.map((ruleStr) => { - const parts = ruleStr.split(/\s+/); - return [parts[0], parts.slice(1)]; - }) - ); - - return { - set: [ - { - path: 'csp.rules', - value: [...parsed].map(([policy, sourceList]) => { - if (sourceList.find((source) => source.includes(NONCE_STRING))) { - addDeprecation({ - message: `csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in ${policy}`, - correctiveActions: { - manualSteps: [`Replace {nonce} syntax with 'self' in ${policy}`], - }, - }); - sourceList = sourceList.filter((source) => !source.includes(NONCE_STRING)); - - // Add 'self' if not present - if (!sourceList.find((source) => source.includes(SELF_STRING))) { - sourceList.push(SELF_STRING); - } - } - - if ( - SELF_POLICIES.includes(policy) && - !sourceList.find((source) => source.includes(SELF_STRING)) - ) { - addDeprecation({ - message: `csp.rules must contain the 'self' source. Automatically adding to ${policy}.`, - correctiveActions: { - manualSteps: [`Add 'self' source to ${policy}.`], - }, - }); - sourceList.push(SELF_STRING); - } - - return `${policy} ${sourceList.join(' ')}`.trim(); - }), - }, - ], - }; - } -}; - -export const coreDeprecationProvider: ConfigDeprecationProvider = ({ rename, unusedFromRoot }) => [ +export const coreDeprecationProvider: ConfigDeprecationProvider = () => [ rewriteCorsSettings, rewriteBasePathDeprecation, - cspRulesDeprecation, ]; diff --git a/src/core/server/csp/config.test.ts b/src/core/server/csp/config.test.ts index 6db93addb7da8..346caf488431c 100644 --- a/src/core/server/csp/config.test.ts +++ b/src/core/server/csp/config.test.ts @@ -80,21 +80,6 @@ describe('config.validate()', () => { ).not.toThrow(); }); - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - script_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -104,6 +89,7 @@ describe('config.validate()', () => { `"[script_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -124,21 +110,6 @@ describe('config.validate()', () => { }); describe(`"worker_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - worker_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -148,6 +119,7 @@ describe('config.validate()', () => { `"[worker_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -168,21 +140,6 @@ describe('config.validate()', () => { }); describe(`"style_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - style_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -192,6 +149,7 @@ describe('config.validate()', () => { `"[style_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -212,21 +170,6 @@ describe('config.validate()', () => { }); describe(`"connect_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - connect_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -236,6 +179,7 @@ describe('config.validate()', () => { `"[connect_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -256,21 +200,6 @@ describe('config.validate()', () => { }); describe(`"default_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - default_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -280,6 +209,7 @@ describe('config.validate()', () => { `"[default_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -300,21 +230,6 @@ describe('config.validate()', () => { }); describe(`"font_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - font_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -324,6 +239,7 @@ describe('config.validate()', () => { `"[font_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -344,21 +260,6 @@ describe('config.validate()', () => { }); describe(`"frame_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - frame_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -368,6 +269,7 @@ describe('config.validate()', () => { `"[frame_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -388,21 +290,6 @@ describe('config.validate()', () => { }); describe(`"img_src"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - img_src: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -412,6 +299,7 @@ describe('config.validate()', () => { `"[img_src]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ @@ -432,21 +320,6 @@ describe('config.validate()', () => { }); describe(`"frame_ancestors"`, () => { - it(`throws if 'rules' is also specified`, () => { - expect(() => - config.schema.validate({ - rules: [ - `script-src 'unsafe-eval' 'self'`, - `worker-src 'unsafe-eval' 'self'`, - `style-src 'unsafe-eval' 'self'`, - ], - frame_ancestors: [`'self'`], - }) - ).toThrowErrorMatchingInlineSnapshot( - `"\\"csp.rules\\" cannot be used when specifying per-directive additions such as \\"script_src\\", \\"worker_src\\" or \\"style_src\\""` - ); - }); - it('throws if using an `nonce-*` value', () => { expect(() => config.schema.validate({ @@ -456,6 +329,7 @@ describe('config.validate()', () => { `"[frame_ancestors]: using \\"nonce-*\\" is considered insecure and is not allowed"` ); }); + it("throws if using `none` or `'none'`", () => { expect(() => config.schema.validate({ diff --git a/src/core/server/csp/config.ts b/src/core/server/csp/config.ts index 3a7cb20985cea..22aa11e4e0c3a 100644 --- a/src/core/server/csp/config.ts +++ b/src/core/server/csp/config.ts @@ -39,7 +39,6 @@ const getDirectiveValueValidator = ({ allowNone, allowNonce }: DirectiveValidati const configSchema = schema.object( { - rules: schema.maybe(schema.arrayOf(schema.string())), script_src: schema.arrayOf(schema.string(), { defaultValue: [], validate: getDirectiveValidator({ allowNone: false, allowNonce: false }), @@ -89,9 +88,6 @@ const configSchema = schema.object( }, { validate: (cspConfig) => { - if (cspConfig.rules && hasDirectiveSpecified(cspConfig)) { - return `"csp.rules" cannot be used when specifying per-directive additions such as "script_src", "worker_src" or "style_src"`; - } const hasUnsafeInlineScriptSrc = cspConfig.script_src.includes(`unsafe-inline`) || cspConfig.script_src.includes(`'unsafe-inline'`); @@ -106,22 +102,6 @@ const configSchema = schema.object( } ); -const hasDirectiveSpecified = (rawConfig: CspConfigType): boolean => { - return Boolean( - rawConfig.script_src.length || - rawConfig.worker_src.length || - rawConfig.style_src.length || - rawConfig.connect_src.length || - rawConfig.default_src.length || - rawConfig.font_src.length || - rawConfig.frame_src.length || - rawConfig.img_src.length || - rawConfig.frame_ancestors.length || - rawConfig.report_uri.length || - rawConfig.report_to.length - ); -}; - /** * @internal */ @@ -132,25 +112,4 @@ export const config: ServiceConfigDescriptor = { // ? https://github.com/elastic/kibana/pull/52251 path: 'csp', schema: configSchema, - deprecations: () => [ - (rawConfig, fromPath, addDeprecation) => { - const cspConfig = rawConfig[fromPath]; - if (cspConfig?.rules) { - addDeprecation({ - message: - '`csp.rules` is deprecated in favor of directive specific configuration. Please use `csp.connect_src`, ' + - '`csp.default_src`, `csp.font_src`, `csp.frame_ancestors`, `csp.frame_src`, `csp.img_src`, ' + - '`csp.report_uri`, `csp.report_to`, `csp.script_src`, `csp.style_src`, and `csp.worker_src` instead.', - correctiveActions: { - manualSteps: [ - `Remove "csp.rules" from the Kibana config file."`, - `Add directive specific configurations to the config file using "csp.connect_src", "csp.default_src", "csp.font_src", ` + - `"csp.frame_ancestors", "csp.frame_src", "csp.img_src", "csp.report_uri", "csp.report_to", "csp.script_src", ` + - `"csp.style_src", and "csp.worker_src".`, - ], - }, - }); - } - }, - ], }; diff --git a/src/core/server/csp/csp_config.test.ts b/src/core/server/csp/csp_config.test.ts index a1bac7d4ae73e..1ec78fae7532d 100644 --- a/src/core/server/csp/csp_config.test.ts +++ b/src/core/server/csp/csp_config.test.ts @@ -34,11 +34,6 @@ describe('CspConfig', () => { CspConfig { "disableEmbedding": false, "header": "script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'", - "rules": Array [ - "script-src 'unsafe-eval' 'self'", - "worker-src blob: 'self'", - "style-src 'unsafe-inline' 'self'", - ], "strict": true, "warnLegacyBrowsers": true, } @@ -50,13 +45,6 @@ describe('CspConfig', () => { }); describe('partial config', () => { - test('allows "rules" to be set and changes header', () => { - const rules = [`foo 'self'`, `bar 'self'`]; - const config = new CspConfig({ ...defaultConfig, rules }); - expect(config.rules).toEqual(rules); - expect(config.header).toMatchInlineSnapshot(`"foo 'self'; bar 'self'"`); - }); - test('allows "strict" to be set', () => { const config = new CspConfig({ ...defaultConfig, strict: false }); expect(config.strict).toEqual(false); @@ -70,67 +58,57 @@ describe('CspConfig', () => { expect(config.warnLegacyBrowsers).not.toEqual(CspConfig.DEFAULT.warnLegacyBrowsers); }); - test('allows "worker_src" to be set and changes header', () => { + test('allows "worker_src" to be set and changes header from defaults', () => { const config = new CspConfig({ ...defaultConfig, - rules: [], worker_src: ['foo', 'bar'], }); - expect(config.rules).toEqual([`worker-src foo bar`]); - expect(config.header).toEqual(`worker-src foo bar`); + expect(config.header).toEqual( + `script-src 'unsafe-eval' 'self'; worker-src blob: 'self' foo bar; style-src 'unsafe-inline' 'self'` + ); }); test('allows "style_src" to be set and changes header', () => { const config = new CspConfig({ ...defaultConfig, - rules: [], style_src: ['foo', 'bar'], }); - expect(config.rules).toEqual([`style-src foo bar`]); - expect(config.header).toEqual(`style-src foo bar`); + + expect(config.header).toEqual( + `script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self' foo bar` + ); }); test('allows "script_src" to be set and changes header', () => { const config = new CspConfig({ ...defaultConfig, - rules: [], script_src: ['foo', 'bar'], }); - expect(config.rules).toEqual([`script-src foo bar`]); - expect(config.header).toEqual(`script-src foo bar`); + + expect(config.header).toEqual( + `script-src 'unsafe-eval' 'self' foo bar; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'` + ); }); test('allows all directives to be set and changes header', () => { const config = new CspConfig({ ...defaultConfig, - rules: [], script_src: ['script', 'foo'], worker_src: ['worker', 'bar'], style_src: ['style', 'dolly'], }); - expect(config.rules).toEqual([ - `script-src script foo`, - `worker-src worker bar`, - `style-src style dolly`, - ]); expect(config.header).toEqual( - `script-src script foo; worker-src worker bar; style-src style dolly` + `script-src 'unsafe-eval' 'self' script foo; worker-src blob: 'self' worker bar; style-src 'unsafe-inline' 'self' style dolly` ); }); - test('applies defaults when `rules` is undefined', () => { + test('appends config directives to defaults', () => { const config = new CspConfig({ ...defaultConfig, - rules: undefined, script_src: ['script'], worker_src: ['worker'], style_src: ['style'], }); - expect(config.rules).toEqual([ - `script-src 'unsafe-eval' 'self' script`, - `worker-src blob: 'self' worker`, - `style-src 'unsafe-inline' 'self' style`, - ]); expect(config.header).toEqual( `script-src 'unsafe-eval' 'self' script; worker-src blob: 'self' worker; style-src 'unsafe-inline' 'self' style` ); @@ -139,25 +117,15 @@ describe('CspConfig', () => { describe('allows "disableEmbedding" to be set', () => { const disableEmbedding = true; - test('and changes rules/header if custom rules are not defined', () => { + test('and changes rules and header', () => { const config = new CspConfig({ ...defaultConfig, disableEmbedding }); expect(config.disableEmbedding).toEqual(disableEmbedding); expect(config.disableEmbedding).not.toEqual(CspConfig.DEFAULT.disableEmbedding); - expect(config.rules).toEqual(expect.arrayContaining([`frame-ancestors 'self'`])); expect(config.header).toMatchInlineSnapshot( `"script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'; frame-ancestors 'self'"` ); }); - test('and does not change rules/header if custom rules are defined', () => { - const rules = [`foo 'self'`, `bar 'self'`]; - const config = new CspConfig({ ...defaultConfig, disableEmbedding, rules }); - expect(config.disableEmbedding).toEqual(disableEmbedding); - expect(config.disableEmbedding).not.toEqual(CspConfig.DEFAULT.disableEmbedding); - expect(config.rules).toEqual(rules); - expect(config.header).toMatchInlineSnapshot(`"foo 'self'; bar 'self'"`); - }); - test('and overrides `frame-ancestors` if set', () => { const config = new CspConfig({ ...defaultConfig, diff --git a/src/core/server/csp/csp_config.ts b/src/core/server/csp/csp_config.ts index 13778088d9df2..f0f968ecd0ceb 100644 --- a/src/core/server/csp/csp_config.ts +++ b/src/core/server/csp/csp_config.ts @@ -16,11 +16,6 @@ const DEFAULT_CONFIG = Object.freeze(config.schema.validate({})); * @public */ export interface ICspConfig { - /** - * The CSP rules used for Kibana. - */ - readonly rules: string[]; - /** * Specify whether browsers that do not support CSP should be * able to use Kibana. Use `true` to block and `false` to allow. @@ -34,8 +29,7 @@ export interface ICspConfig { readonly warnLegacyBrowsers: boolean; /** - * Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled *and* no custom rules have been - * defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. + * Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. */ readonly disableEmbedding: boolean; @@ -54,7 +48,6 @@ export class CspConfig implements ICspConfig { static readonly DEFAULT = new CspConfig(DEFAULT_CONFIG); readonly #directives: CspDirectives; - public readonly rules: string[]; public readonly strict: boolean; public readonly warnLegacyBrowsers: boolean; public readonly disableEmbedding: boolean; @@ -66,14 +59,11 @@ export class CspConfig implements ICspConfig { */ constructor(rawCspConfig: CspConfigType) { this.#directives = CspDirectives.fromConfig(rawCspConfig); - if (!rawCspConfig.rules?.length && rawCspConfig.disableEmbedding) { + if (rawCspConfig.disableEmbedding) { this.#directives.clearDirectiveValues('frame-ancestors'); this.#directives.addDirectiveValue('frame-ancestors', `'self'`); } - - this.rules = this.#directives.getRules(); this.header = this.#directives.getCspHeader(); - this.strict = rawCspConfig.strict; this.warnLegacyBrowsers = rawCspConfig.warnLegacyBrowsers; this.disableEmbedding = rawCspConfig.disableEmbedding; diff --git a/src/core/server/csp/csp_directives.test.ts b/src/core/server/csp/csp_directives.test.ts index 1077b6ea9f3cd..f4a9e256e2f98 100644 --- a/src/core/server/csp/csp_directives.test.ts +++ b/src/core/server/csp/csp_directives.test.ts @@ -11,33 +11,12 @@ import { config as cspConfig } from './config'; describe('CspDirectives', () => { describe('#addDirectiveValue', () => { - it('properly updates the rules', () => { - const directives = new CspDirectives(); - directives.addDirectiveValue('style-src', 'foo'); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "style-src foo", - ] - `); - - directives.addDirectiveValue('style-src', 'bar'); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "style-src foo bar", - ] - `); - }); - it('properly updates the header', () => { const directives = new CspDirectives(); directives.addDirectiveValue('style-src', 'foo'); - expect(directives.getCspHeader()).toMatchInlineSnapshot(`"style-src foo"`); directives.addDirectiveValue('style-src', 'bar'); - expect(directives.getCspHeader()).toMatchInlineSnapshot(`"style-src foo bar"`); }); @@ -50,12 +29,6 @@ describe('CspDirectives', () => { expect(directives.getCspHeader()).toMatchInlineSnapshot( `"style-src foo bar; worker-src dolly"` ); - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "style-src foo bar", - "worker-src dolly", - ] - `); }); it('removes duplicates', () => { @@ -65,11 +38,6 @@ describe('CspDirectives', () => { directives.addDirectiveValue('style-src', 'bar'); expect(directives.getCspHeader()).toMatchInlineSnapshot(`"style-src foo bar"`); - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "style-src foo bar", - ] - `); }); it('automatically adds single quotes for keywords', () => { @@ -106,18 +74,6 @@ describe('CspDirectives', () => { }); describe('#fromConfig', () => { - it('returns the correct rules for the default config', () => { - const config = cspConfig.schema.validate({}); - const directives = CspDirectives.fromConfig(config); - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'unsafe-eval' 'self'", - "worker-src blob: 'self'", - "style-src 'unsafe-inline' 'self'", - ] - `); - }); - it('returns the correct header for the default config', () => { const config = cspConfig.schema.validate({}); const directives = CspDirectives.fromConfig(config); @@ -126,75 +82,6 @@ describe('CspDirectives', () => { ); }); - it('handles config with rules', () => { - const config = cspConfig.schema.validate({ - rules: [`script-src 'self' http://foo.com`, `worker-src 'self'`], - }); - const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'self' http://foo.com", - "worker-src 'self'", - ] - `); - expect(directives.getCspHeader()).toMatchInlineSnapshot( - `"script-src 'self' http://foo.com; worker-src 'self'"` - ); - }); - - it('adds single quotes for keyword for rules', () => { - const config = cspConfig.schema.validate({ - rules: [`script-src self http://foo.com`, `worker-src self`], - }); - const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'self' http://foo.com", - "worker-src 'self'", - ] - `); - expect(directives.getCspHeader()).toMatchInlineSnapshot( - `"script-src 'self' http://foo.com; worker-src 'self'"` - ); - }); - - it('handles multiple whitespaces when parsing rules', () => { - const config = cspConfig.schema.validate({ - rules: [` script-src 'self' http://foo.com `, ` worker-src 'self' `], - }); - const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'self' http://foo.com", - "worker-src 'self'", - ] - `); - expect(directives.getCspHeader()).toMatchInlineSnapshot( - `"script-src 'self' http://foo.com; worker-src 'self'"` - ); - }); - - it('supports unregistered directives', () => { - const config = cspConfig.schema.validate({ - rules: [`script-src 'self' http://foo.com`, `img-src 'self'`, 'foo bar'], - }); - const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'self' http://foo.com", - "img-src 'self'", - "foo bar", - ] - `); - expect(directives.getCspHeader()).toMatchInlineSnapshot( - `"script-src 'self' http://foo.com; img-src 'self'; foo bar"` - ); - }); - it('adds default value for config with directives', () => { const config = cspConfig.schema.validate({ script_src: [`baz`], @@ -203,13 +90,6 @@ describe('CspDirectives', () => { }); const directives = CspDirectives.fromConfig(config); - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'unsafe-eval' 'self' baz", - "worker-src blob: 'self' foo", - "style-src 'unsafe-inline' 'self' bar dolly", - ] - `); expect(directives.getCspHeader()).toMatchInlineSnapshot( `"script-src 'unsafe-eval' 'self' baz; worker-src blob: 'self' foo; style-src 'unsafe-inline' 'self' bar dolly"` ); @@ -227,22 +107,9 @@ describe('CspDirectives', () => { report_to: [`report-to`], }); const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'unsafe-eval' 'self'", - "worker-src blob: 'self'", - "style-src 'unsafe-inline' 'self'", - "connect-src 'self' connect-src", - "default-src 'self' default-src", - "font-src 'self' font-src", - "frame-src 'self' frame-src", - "img-src 'self' img-src", - "frame-ancestors 'self' frame-ancestors", - "report-uri report-uri", - "report-to report-to", - ] - `); + expect(directives.getCspHeader()).toMatchInlineSnapshot( + `"script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'; connect-src 'self' connect-src; default-src 'self' default-src; font-src 'self' font-src; frame-src 'self' frame-src; img-src 'self' img-src; frame-ancestors 'self' frame-ancestors; report-uri report-uri; report-to report-to"` + ); }); it('adds single quotes for keywords in added directives', () => { @@ -250,14 +117,6 @@ describe('CspDirectives', () => { script_src: [`unsafe-hashes`], }); const directives = CspDirectives.fromConfig(config); - - expect(directives.getRules()).toMatchInlineSnapshot(` - Array [ - "script-src 'unsafe-eval' 'self' 'unsafe-hashes'", - "worker-src blob: 'self'", - "style-src 'unsafe-inline' 'self'", - ] - `); expect(directives.getCspHeader()).toMatchInlineSnapshot( `"script-src 'unsafe-eval' 'self' 'unsafe-hashes'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'"` ); diff --git a/src/core/server/csp/csp_directives.ts b/src/core/server/csp/csp_directives.ts index 9e3b60f7f1e4f..d656210a054f9 100644 --- a/src/core/server/csp/csp_directives.ts +++ b/src/core/server/csp/csp_directives.ts @@ -22,7 +22,7 @@ export type CspDirectiveName = | 'report-to'; /** - * The default rules that are always applied + * The default directives rules that are always applied */ export const defaultRules: Partial> = { 'script-src': [`'unsafe-eval'`, `'self'`], @@ -58,21 +58,18 @@ export class CspDirectives { } getCspHeader() { - return this.getRules().join('; '); - } - - getRules() { - return [...this.directives.entries()].map(([name, values]) => { - return [name, ...values].join(' '); - }); + return [...this.directives.entries()] + .map(([name, values]) => { + return [name, ...values].join(' '); + }) + .join('; '); } static fromConfig(config: CspConfigType): CspDirectives { const cspDirectives = new CspDirectives(); - // adding `csp.rules` or `default` rules - const initialRules = config.rules ? parseRules(config.rules) : { ...defaultRules }; - Object.entries(initialRules).forEach(([key, values]) => { + // combining `default` directive configurations + Object.entries(defaultRules).forEach(([key, values]) => { values?.forEach((value) => { cspDirectives.addDirectiveValue(key as CspDirectiveName, value); }); @@ -91,15 +88,6 @@ export class CspDirectives { } } -const parseRules = (rules: string[]): Partial> => { - const directives: Partial> = {}; - rules.forEach((rule) => { - const [name, ...values] = rule.replace(/\s+/g, ' ').trim().split(' '); - directives[name as CspDirectiveName] = values; - }); - return directives; -}; - const parseConfigDirectives = (cspConfig: CspConfigType): Map => { const map = new Map(); diff --git a/src/core/server/http_resources/integration_tests/http_resources_service.test.ts b/src/core/server/http_resources/integration_tests/http_resources_service.test.ts index 6f4f3c9c6e985..3b254df929037 100644 --- a/src/core/server/http_resources/integration_tests/http_resources_service.test.ts +++ b/src/core/server/http_resources/integration_tests/http_resources_service.test.ts @@ -12,12 +12,10 @@ import * as kbnTestServer from '../../../test_helpers/kbn_server'; describe('http resources service', () => { describe('register', () => { let root: ReturnType; - const defaultCspRules = "script-src 'self'"; + const defaultCspRules = + "script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'"; beforeEach(async () => { root = kbnTestServer.createRoot({ - csp: { - rules: [defaultCspRules], - }, plugins: { initialize: false }, elasticsearch: { skipStartupConnectionCheck: true }, }); @@ -44,7 +42,7 @@ describe('http resources service', () => { expect(response.text.length).toBeGreaterThan(0); }); - it('attaches CSP header', async () => { + it('applies default CSP header', async () => { const { http, httpResources } = await root.setup(); const router = http.createRouter(''); diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index a1fd69f5e1c7e..fb16e889a19c7 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -754,8 +754,6 @@ export class CspConfig implements ICspConfig { // (undocumented) readonly header: string; // (undocumented) - readonly rules: string[]; - // (undocumented) readonly strict: boolean; // (undocumented) readonly warnLegacyBrowsers: boolean; @@ -1135,7 +1133,6 @@ export type IContextProvider { expect((await collector.fetch(mockedFetchContext)).warnLegacyBrowsers).toEqual(false); }); - test('fetches whether the csp rules have been changed or not', async () => { + test("fetches whether the csp directives's rules have been changed or not", async () => { const collector = new Collector(logger, createCspCollector(httpMock)); expect((await collector.fetch(mockedFetchContext)).rulesChangedFromDefault).toEqual(false); - updateCsp({ rules: ['not', 'default'] }); + updateCsp({ disableEmbedding: true }); expect((await collector.fetch(mockedFetchContext)).rulesChangedFromDefault).toEqual(true); }); test('does not include raw csp rules under any property names', async () => { const collector = new Collector(logger, createCspCollector(httpMock)); - // It's important that we do not send the value of csp.rules here as it + // It's important that we do not send the raw values of csp cirectives here as they // can be customized with values that can be identifiable to given // installs, such as URLs // - // We use a snapshot here to ensure csp.rules isn't finding its way into the + // We use a snapshot here to ensure raw values aren't finding their way into the // payload under some new and unexpected variable name (e.g. cspRules). expect(await collector.fetch(mockedFetchContext)).toMatchInlineSnapshot(` Object { From c926b14c32307a12b31938641594356655faf360 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Mon, 11 Oct 2021 21:06:35 -0400 Subject: [PATCH 30/73] [Alerting] Showing last execution duration on Rule Management view (#113935) * Adding last duration to execution status and returning in alerting routes * Fixing types * Adding helper function to format duration * Returning rule timeout value in list rules API * Updating rules table to add duration column and tweaks to match mockup * Updating rules table to add duration column and tweaks to match mockup * i18n fix * Only showing duration warning if duration is long * Unit tests * i18n fix * Fixing functional test * Aligning warning icon * Reset last duration when rule is disabled then reenabled * Fixing functional test * Fixing functional test * Restoring muted badge. Fixing scss * Dont show muted badge if rule is disabled * Moving disabled icontip to right of rule name * Updating tooltips * Updating last run Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/alerting/common/alert.ts | 1 + x-pack/plugins/alerting/common/alert_type.ts | 1 + .../alerting/common/parse_duration.test.ts | 39 ++- .../plugins/alerting/common/parse_duration.ts | 16 + .../server/lib/alert_execution_status.test.ts | 49 +++ .../server/lib/alert_execution_status.ts | 20 +- .../alerting/server/routes/create_rule.ts | 3 +- .../alerting/server/routes/find_rules.ts | 3 +- .../alerting/server/routes/get_rule.ts | 3 +- .../alerting/server/routes/resolve_rule.ts | 3 +- .../alerting/server/routes/rule_types.test.ts | 3 + .../alerting/server/routes/rule_types.ts | 2 + .../alerting/server/routes/update_rule.ts | 1 + .../server/rule_type_registry.test.ts | 2 + .../alerting/server/rule_type_registry.ts | 3 + .../server/rules_client/rules_client.ts | 1 + .../server/rules_client/tests/enable.test.ts | 2 + .../server/saved_objects/mappings.json | 3 + .../server/task_runner/task_runner.test.ts | 2 + .../server/task_runner/task_runner.ts | 5 + x-pack/plugins/alerting/server/types.ts | 1 + .../translations/translations/ja-JP.json | 12 +- .../translations/translations/zh-CN.json | 14 +- .../lib/alert_api/common_transformations.ts | 2 + .../application/lib/alert_api/rule_types.ts | 2 + .../components/alert_status_filter.tsx | 4 +- .../alerts_list/components/alerts_list.scss | 11 + .../components/alerts_list.test.tsx | 57 +++- .../alerts_list/components/alerts_list.tsx | 311 ++++++++++++------ .../collapsed_item_actions.test.tsx | 2 +- .../components/rule_enabled_switch.test.tsx | 4 +- .../triggers_actions_ui/public/types.ts | 3 +- .../tests/alerting/rule_types.ts | 2 + .../spaces_only/tests/alerting/rule_types.ts | 2 + .../apps/triggers_actions_ui/alerts_list.ts | 130 +++----- .../page_objects/triggers_actions_ui_page.ts | 12 +- 36 files changed, 512 insertions(+), 219 deletions(-) diff --git a/x-pack/plugins/alerting/common/alert.ts b/x-pack/plugins/alerting/common/alert.ts index 1274e7b95b114..bf0c8e382c9d4 100644 --- a/x-pack/plugins/alerting/common/alert.ts +++ b/x-pack/plugins/alerting/common/alert.ts @@ -35,6 +35,7 @@ export enum AlertExecutionStatusErrorReasons { export interface AlertExecutionStatus { status: AlertExecutionStatuses; lastExecutionDate: Date; + lastDuration?: number; error?: { reason: AlertExecutionStatusErrorReasons; message: string; diff --git a/x-pack/plugins/alerting/common/alert_type.ts b/x-pack/plugins/alerting/common/alert_type.ts index d71540b4418e8..1b0ac28c9fa74 100644 --- a/x-pack/plugins/alerting/common/alert_type.ts +++ b/x-pack/plugins/alerting/common/alert_type.ts @@ -21,6 +21,7 @@ export interface AlertType< producer: string; minimumLicenseRequired: LicenseType; isExportable: boolean; + ruleTaskTimeout?: string; defaultScheduleInterval?: string; minimumScheduleInterval?: string; } diff --git a/x-pack/plugins/alerting/common/parse_duration.test.ts b/x-pack/plugins/alerting/common/parse_duration.test.ts index 9fbb662e21147..e68a3f479f228 100644 --- a/x-pack/plugins/alerting/common/parse_duration.test.ts +++ b/x-pack/plugins/alerting/common/parse_duration.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { parseDuration, getDurationNumberInItsUnit, getDurationUnitValue } from './parse_duration'; +import { + parseDuration, + formatDuration, + getDurationNumberInItsUnit, + getDurationUnitValue, +} from './parse_duration'; test('parses seconds', () => { const result = parseDuration('10s'); @@ -39,6 +44,38 @@ test('throws error when suffix is missing', () => { ); }); +test('formats seconds', () => { + const result = formatDuration('10s'); + expect(result).toEqual('10 sec'); +}); + +test('formats minutes', () => { + const result = formatDuration('10m'); + expect(result).toEqual('10 min'); +}); + +test('formats hours', () => { + const result = formatDuration('10h'); + expect(result).toEqual('10 hr'); +}); + +test('formats days', () => { + const result = formatDuration('10d'); + expect(result).toEqual('10 day'); +}); + +test('format throws error when the format is invalid', () => { + expect(() => formatDuration('10x')).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration \\"10x\\". Durations must be of the form {number}x. Example: 5s, 5m, 5h or 5d\\""` + ); +}); + +test('format throws error when suffix is missing', () => { + expect(() => formatDuration('1000')).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration \\"1000\\". Durations must be of the form {number}x. Example: 5s, 5m, 5h or 5d\\""` + ); +}); + test('throws error when 0 based', () => { expect(() => parseDuration('0s')).toThrowErrorMatchingInlineSnapshot( `"Invalid duration \\"0s\\". Durations must be of the form {number}x. Example: 5s, 5m, 5h or 5d\\""` diff --git a/x-pack/plugins/alerting/common/parse_duration.ts b/x-pack/plugins/alerting/common/parse_duration.ts index 3494a48fc8ab9..af4f1d2c14099 100644 --- a/x-pack/plugins/alerting/common/parse_duration.ts +++ b/x-pack/plugins/alerting/common/parse_duration.ts @@ -27,6 +27,22 @@ export function parseDuration(duration: string): number { ); } +export function formatDuration(duration: string): string { + const parsed = parseInt(duration, 10); + if (isSeconds(duration)) { + return `${parsed} sec`; + } else if (isMinutes(duration)) { + return `${parsed} min`; + } else if (isHours(duration)) { + return `${parsed} hr`; + } else if (isDays(duration)) { + return `${parsed} day`; + } + throw new Error( + `Invalid duration "${duration}". Durations must be of the form {number}x. Example: 5s, 5m, 5h or 5d"` + ); +} + export function getDurationNumberInItsUnit(duration: string): number { return parseInt(duration.replace(/[^0-9.]/g, ''), 10); } diff --git a/x-pack/plugins/alerting/server/lib/alert_execution_status.test.ts b/x-pack/plugins/alerting/server/lib/alert_execution_status.test.ts index 0a8d5632f169f..93cf0c656c692 100644 --- a/x-pack/plugins/alerting/server/lib/alert_execution_status.test.ts +++ b/x-pack/plugins/alerting/server/lib/alert_execution_status.test.ts @@ -81,6 +81,7 @@ describe('AlertExecutionStatus', () => { expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status })).toMatchInlineSnapshot(` Object { "error": null, + "lastDuration": 0, "lastExecutionDate": "2020-09-03T16:26:58.000Z", "status": "ok", } @@ -95,11 +96,24 @@ describe('AlertExecutionStatus', () => { "message": "wops", "reason": "decrypt", }, + "lastDuration": 0, "lastExecutionDate": "2020-09-03T16:26:58.000Z", "status": "ok", } `); }); + + test('status with a duration', () => { + expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status, lastDuration: 1234 })) + .toMatchInlineSnapshot(` + Object { + "error": null, + "lastDuration": 1234, + "lastExecutionDate": "2020-09-03T16:26:58.000Z", + "status": "ok", + } + `); + }); }); describe('alertExecutionStatusFromRaw()', () => { @@ -177,6 +191,41 @@ describe('AlertExecutionStatus', () => { } `); }); + + test('valid status, date and duration', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + status, + lastExecutionDate: date, + lastDuration: 1234, + }); + expect(result).toMatchInlineSnapshot(` + Object { + "lastDuration": 1234, + "lastExecutionDate": 2020-09-03T16:26:58.000Z, + "status": "active", + } + `); + }); + + test('valid status, date, error and duration', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + status, + lastExecutionDate: date, + error, + lastDuration: 1234, + }); + expect(result).toMatchInlineSnapshot(` + Object { + "error": Object { + "message": "wops", + "reason": "execute", + }, + "lastDuration": 1234, + "lastExecutionDate": 2020-09-03T16:26:58.000Z, + "status": "active", + } + `); + }); }); }); diff --git a/x-pack/plugins/alerting/server/lib/alert_execution_status.ts b/x-pack/plugins/alerting/server/lib/alert_execution_status.ts index 47dfc659307a2..82d8514331704 100644 --- a/x-pack/plugins/alerting/server/lib/alert_execution_status.ts +++ b/x-pack/plugins/alerting/server/lib/alert_execution_status.ts @@ -32,11 +32,13 @@ export function executionStatusFromError(error: Error): AlertExecutionStatus { export function alertExecutionStatusToRaw({ lastExecutionDate, + lastDuration, status, error, }: AlertExecutionStatus): RawAlertExecutionStatus { return { lastExecutionDate: lastExecutionDate.toISOString(), + lastDuration: lastDuration ?? 0, status, // explicitly setting to null (in case undefined) due to partial update concerns error: error ?? null, @@ -50,7 +52,7 @@ export function alertExecutionStatusFromRaw( ): AlertExecutionStatus | undefined { if (!rawAlertExecutionStatus) return undefined; - const { lastExecutionDate, status = 'unknown', error } = rawAlertExecutionStatus; + const { lastExecutionDate, lastDuration, status = 'unknown', error } = rawAlertExecutionStatus; let parsedDateMillis = lastExecutionDate ? Date.parse(lastExecutionDate) : Date.now(); if (isNaN(parsedDateMillis)) { @@ -60,12 +62,20 @@ export function alertExecutionStatusFromRaw( parsedDateMillis = Date.now(); } - const parsedDate = new Date(parsedDateMillis); + const executionStatus: AlertExecutionStatus = { + status, + lastExecutionDate: new Date(parsedDateMillis), + }; + + if (null != lastDuration) { + executionStatus.lastDuration = lastDuration; + } + if (error) { - return { lastExecutionDate: parsedDate, status, error }; - } else { - return { lastExecutionDate: parsedDate, status }; + executionStatus.error = error; } + + return executionStatus; } export const getAlertExecutionStatusPending = (lastExecutionDate: string) => ({ diff --git a/x-pack/plugins/alerting/server/routes/create_rule.ts b/x-pack/plugins/alerting/server/routes/create_rule.ts index 55a98eb56bee4..ed124bfbd3a2d 100644 --- a/x-pack/plugins/alerting/server/routes/create_rule.ts +++ b/x-pack/plugins/alerting/server/routes/create_rule.ts @@ -67,7 +67,7 @@ const rewriteBodyRes: RewriteResponseCase> = ({ notifyWhen, muteAll, mutedInstanceIds, - executionStatus: { lastExecutionDate, ...executionStatus }, + executionStatus: { lastExecutionDate, lastDuration, ...executionStatus }, ...rest }) => ({ ...rest, @@ -84,6 +84,7 @@ const rewriteBodyRes: RewriteResponseCase> = ({ execution_status: { ...executionStatus, last_execution_date: lastExecutionDate, + last_duration: lastDuration, }, actions: actions.map(({ group, id, actionTypeId, params }) => ({ group, diff --git a/x-pack/plugins/alerting/server/routes/find_rules.ts b/x-pack/plugins/alerting/server/routes/find_rules.ts index a4a066728555d..7826e924acdc5 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.ts +++ b/x-pack/plugins/alerting/server/routes/find_rules.ts @@ -93,8 +93,9 @@ const rewriteBodyRes: RewriteResponseCase> = ({ muted_alert_ids: mutedInstanceIds, scheduled_task_id: scheduledTaskId, execution_status: executionStatus && { - ...omit(executionStatus, 'lastExecutionDate'), + ...omit(executionStatus, 'lastExecutionDate', 'lastDuration'), last_execution_date: executionStatus.lastExecutionDate, + last_duration: executionStatus.lastDuration, }, actions: actions.map(({ group, id, actionTypeId, params }) => ({ group, diff --git a/x-pack/plugins/alerting/server/routes/get_rule.ts b/x-pack/plugins/alerting/server/routes/get_rule.ts index c860ae725a253..4da9410517fe1 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule.ts @@ -48,8 +48,9 @@ const rewriteBodyRes: RewriteResponseCase> = ({ muted_alert_ids: mutedInstanceIds, scheduled_task_id: scheduledTaskId, execution_status: executionStatus && { - ...omit(executionStatus, 'lastExecutionDate'), + ...omit(executionStatus, 'lastExecutionDate', 'lastDuration'), last_execution_date: executionStatus.lastExecutionDate, + last_duration: executionStatus.lastDuration, }, actions: actions.map(({ group, id, actionTypeId, params }) => ({ group, diff --git a/x-pack/plugins/alerting/server/routes/resolve_rule.ts b/x-pack/plugins/alerting/server/routes/resolve_rule.ts index 011d28780e718..a31cf5059b99f 100644 --- a/x-pack/plugins/alerting/server/routes/resolve_rule.ts +++ b/x-pack/plugins/alerting/server/routes/resolve_rule.ts @@ -48,8 +48,9 @@ const rewriteBodyRes: RewriteResponseCase muted_alert_ids: mutedInstanceIds, scheduled_task_id: scheduledTaskId, execution_status: executionStatus && { - ...omit(executionStatus, 'lastExecutionDate'), + ...omit(executionStatus, 'lastExecutionDate', 'lastDuration'), last_execution_date: executionStatus.lastExecutionDate, + last_duration: executionStatus.lastDuration, }, actions: actions.map(({ group, id, actionTypeId, params }) => ({ group, diff --git a/x-pack/plugins/alerting/server/routes/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule_types.test.ts index e4247c9de6cad..7deb2704fb7ec 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.test.ts @@ -49,6 +49,7 @@ describe('ruleTypesRoute', () => { defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', isExportable: true, + ruleTaskTimeout: '10m', recoveryActionGroup: RecoveredActionGroup, authorizedConsumers: {}, actionVariables: { @@ -76,6 +77,7 @@ describe('ruleTypesRoute', () => { minimum_license_required: 'basic', minimum_schedule_interval: '1m', is_exportable: true, + rule_task_timeout: '10m', recovery_action_group: RecoveredActionGroup, authorized_consumers: {}, action_variables: { @@ -118,6 +120,7 @@ describe('ruleTypesRoute', () => { "id": "recovered", "name": "Recovered", }, + "rule_task_timeout": "10m", }, ], } diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts index 72502b25e9aff..d1f24538d76d8 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -20,6 +20,7 @@ const rewriteBodyRes: RewriteResponseCase = (result defaultActionGroupId, minimumLicenseRequired, isExportable, + ruleTaskTimeout, actionVariables, authorizedConsumers, minimumScheduleInterval, @@ -33,6 +34,7 @@ const rewriteBodyRes: RewriteResponseCase = (result default_action_group_id: defaultActionGroupId, minimum_license_required: minimumLicenseRequired, is_exportable: isExportable, + rule_task_timeout: ruleTaskTimeout, action_variables: actionVariables, authorized_consumers: authorizedConsumers, minimum_schedule_interval: minimumScheduleInterval, diff --git a/x-pack/plugins/alerting/server/routes/update_rule.ts b/x-pack/plugins/alerting/server/routes/update_rule.ts index 6e8024a0ddbf5..007d24bb8251b 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule.ts @@ -88,6 +88,7 @@ const rewriteBodyRes: RewriteResponseCase> = ({ execution_status: { status: executionStatus.status, last_execution_date: executionStatus.lastExecutionDate, + last_duration: executionStatus.lastDuration, }, } : {}), diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index beb5f264eb725..895a5047339ef 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -494,6 +494,7 @@ describe('list()', () => { ], defaultActionGroupId: 'testActionGroup', isExportable: true, + ruleTaskTimeout: '20m', minimumLicenseRequired: 'basic', executor: jest.fn(), producer: 'alerts', @@ -530,6 +531,7 @@ describe('list()', () => { "id": "recovered", "name": "Recovered", }, + "ruleTaskTimeout": "20m", }, } `); diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index db02edf4d19dd..452729a9a01e9 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -48,6 +48,7 @@ export interface RegistryRuleType | 'producer' | 'minimumLicenseRequired' | 'isExportable' + | 'ruleTaskTimeout' | 'minimumScheduleInterval' | 'defaultScheduleInterval' > { @@ -327,6 +328,7 @@ export class RuleTypeRegistry { producer, minimumLicenseRequired, isExportable, + ruleTaskTimeout, minimumScheduleInterval, defaultScheduleInterval, }, @@ -340,6 +342,7 @@ export class RuleTypeRegistry { producer, minimumLicenseRequired, isExportable, + ruleTaskTimeout, minimumScheduleInterval, defaultScheduleInterval, enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType( diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 2228b5d27910f..2492517f4bdc3 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -1133,6 +1133,7 @@ export class RulesClient { updatedAt: new Date().toISOString(), executionStatus: { status: 'pending', + lastDuration: 0, lastExecutionDate: new Date().toISOString(), error: null, }, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts index 7b8fbff4fca5a..5e3f148c2fc11 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts @@ -260,6 +260,7 @@ describe('enable()', () => { ], executionStatus: { status: 'pending', + lastDuration: 0, lastExecutionDate: '2019-02-12T21:01:22.479Z', error: null, }, @@ -369,6 +370,7 @@ describe('enable()', () => { ], executionStatus: { status: 'pending', + lastDuration: 0, lastExecutionDate: '2019-02-12T21:01:22.479Z', error: null, }, diff --git a/x-pack/plugins/alerting/server/saved_objects/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json index 21d7a05f2a76d..05e221a47499c 100644 --- a/x-pack/plugins/alerting/server/saved_objects/mappings.json +++ b/x-pack/plugins/alerting/server/saved_objects/mappings.json @@ -101,6 +101,9 @@ "lastExecutionDate": { "type": "date" }, + "lastDuration": { + "type": "long" + }, "error": { "properties": { "reason": { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index bc477136ec111..c5ccc909eff46 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -338,6 +338,7 @@ describe('Task Runner', () => { { executionStatus: { error: null, + lastDuration: 0, lastExecutionDate: '1970-01-01T00:00:00.000Z', status: 'ok', }, @@ -4394,6 +4395,7 @@ describe('Task Runner', () => { { executionStatus: { error: null, + lastDuration: 0, lastExecutionDate: '1970-01-01T00:00:00.000Z', status: 'ok', }, diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 28cc0f2dba4d0..edf9bfe1b4846 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -585,6 +585,11 @@ export class TaskRunner< event.kibana.alerting = event.kibana.alerting || {}; event.kibana.alerting.status = executionStatus.status; + // Copy duration into execution status if available + if (null != event.event?.duration) { + executionStatus.lastDuration = Math.round(event.event?.duration / Millis2Nanos); + } + // if executionStatus indicates an error, fill in fields in // event from it if (executionStatus.error) { diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 1dc8291d28756..82bb94b121840 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -185,6 +185,7 @@ export interface AlertMeta extends SavedObjectAttributes { export interface RawAlertExecutionStatus extends SavedObjectAttributes { status: AlertExecutionStatuses; lastExecutionDate: string; + lastDuration?: number; error: null | { reason: AlertExecutionStatusErrorReasons; message: string; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f36f3abe66a4c..fbd9352fb427f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -25336,7 +25336,6 @@ "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "ルールの実行中にエラーが発生しました。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "不明な理由でエラーが発生しました。", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "アクション", - "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTitle": "アクション", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "型", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.deleteAriaLabel": "削除", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.deleteButtonTooltip": "削除", @@ -25347,7 +25346,6 @@ "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名前", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.scheduleTitle": "次の間隔で実行", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle": "ステータス", - "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.tagsText": "タグ", "xpack.triggersActionsUI.sections.alertsList.alertStatusActive": "アクティブ", "xpack.triggersActionsUI.sections.alertsList.alertStatusError": "エラー", "xpack.triggersActionsUI.sections.alertsList.alertStatusFilterLabel": "ステータス", @@ -25383,11 +25381,11 @@ "xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle": "検索", "xpack.triggersActionsUI.sections.alertsList.singleTitle": "ルール", "xpack.triggersActionsUI.sections.alertsList.totalItemsCountDescription": "{pageSize}/{totalItemCount}件のルールを表示しています。", - "xpack.triggersActionsUI.sections.alertsList.totalStausesActiveDescription": "有効:{totalStausesActive}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesErrorDescription": "エラー:{totalStausesError}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesOkDescription": "Ok:{totalStausesOk}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesPendingDescription": "保留中:{totalStausesPending}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesUnknownDescription": "不明:{totalStausesUnknown}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesActiveDescription": "有効:{totalStatusesActive}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesErrorDescription": "エラー:{totalStatusesError}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesOkDescription": "Ok:{totalStatusesOk}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesPendingDescription": "保留中:{totalStatusesPending}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesUnknownDescription": "不明:{totalStatusesUnknown}", "xpack.triggersActionsUI.sections.alertsList.typeFilterLabel": "型", "xpack.triggersActionsUI.sections.alertsList.unableToLoadConnectorTypesMessage": "コネクタータイプを読み込めません", "xpack.triggersActionsUI.sections.alertsList.unableToLoadRulesMessage": "ルールを読み込めません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 11b951b97ae05..9408bb85db879 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25763,7 +25763,6 @@ "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "运行规则时发生错误。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "由于未知原因发生错误。", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "操作", - "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTitle": "操作", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "类型", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.deleteAriaLabel": "删除", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.deleteButtonTooltip": "删除", @@ -25774,7 +25773,6 @@ "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名称", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.scheduleTitle": "运行间隔", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle": "状态", - "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.tagsText": "标签", "xpack.triggersActionsUI.sections.alertsList.alertStatusActive": "活动", "xpack.triggersActionsUI.sections.alertsList.alertStatusError": "错误", "xpack.triggersActionsUI.sections.alertsList.alertStatusFilterLabel": "状态", @@ -25782,7 +25780,7 @@ "xpack.triggersActionsUI.sections.alertsList.alertStatusOk": "确定", "xpack.triggersActionsUI.sections.alertsList.alertStatusPending": "待处理", "xpack.triggersActionsUI.sections.alertsList.alertStatusUnknown": "未知", - "xpack.triggersActionsUI.sections.alertsList.attentionBannerTitle": "{totalStausesError, plural, other {# 个规则}}中有错误。", + "xpack.triggersActionsUI.sections.alertsList.attentionBannerTitle": "{totalStatusesError, plural, other {# 个规则}}中有错误。", "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.buttonTitle": "管理规则", "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.deleteAllTitle": "删除", "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.disableAllTitle": "禁用", @@ -25811,11 +25809,11 @@ "xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle": "搜索", "xpack.triggersActionsUI.sections.alertsList.singleTitle": "规则", "xpack.triggersActionsUI.sections.alertsList.totalItemsCountDescription": "正在显示:{pageSize} 个规则(共 {totalItemCount} 个)。", - "xpack.triggersActionsUI.sections.alertsList.totalStausesActiveDescription": "活动:{totalStausesActive}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesErrorDescription": "错误:{totalStausesError}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesOkDescription": "确定:{totalStausesOk}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesPendingDescription": "待处理:{totalStausesPending}", - "xpack.triggersActionsUI.sections.alertsList.totalStausesUnknownDescription": "未知:{totalStausesUnknown}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesActiveDescription": "活动:{totalStatusesActive}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesErrorDescription": "错误:{totalStatusesError}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesOkDescription": "确定:{totalStatusesOk}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesPendingDescription": "待处理:{totalStatusesPending}", + "xpack.triggersActionsUI.sections.alertsList.totalStatusesUnknownDescription": "未知:{totalStatusesUnknown}", "xpack.triggersActionsUI.sections.alertsList.typeFilterLabel": "类型", "xpack.triggersActionsUI.sections.alertsList.unableToLoadConnectorTypesMessage": "无法加载连接器类型", "xpack.triggersActionsUI.sections.alertsList.unableToLoadRulesMessage": "无法加载规则", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/common_transformations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/common_transformations.ts index 5049a37c317dd..6369937e59377 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/common_transformations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/common_transformations.ts @@ -22,9 +22,11 @@ const transformAction: RewriteRequestCase = ({ const transformExecutionStatus: RewriteRequestCase = ({ last_execution_date: lastExecutionDate, + last_duration: lastDuration, ...rest }) => ({ lastExecutionDate, + lastDuration, ...rest, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/rule_types.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/rule_types.ts index 54369d7959c93..67d317643ec06 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/rule_types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/rule_types.ts @@ -21,6 +21,7 @@ const rewriteBodyReq: RewriteRequestCase = ({ minimum_license_required: minimumLicenseRequired, action_variables: actionVariables, authorized_consumers: authorizedConsumers, + rule_task_timeout: ruleTaskTimeout, ...rest }: AsApiContract) => ({ enabledInLicense, @@ -30,6 +31,7 @@ const rewriteBodyReq: RewriteRequestCase = ({ minimumLicenseRequired, actionVariables, authorizedConsumers, + ruleTaskTimeout, ...rest, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx index aca111df97e34..50295548f9aa4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx @@ -99,10 +99,10 @@ export function getHealthColor(status: AlertExecutionStatuses) { case 'error': return 'danger'; case 'ok': - return 'subdued'; + return 'primary'; case 'pending': return 'accent'; default: - return 'warning'; + return 'subdued'; } } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.scss index c0e46b77b4156..138605421f202 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.scss @@ -31,3 +31,14 @@ opacity: 1; /* 2 */ } } + +.ruleDurationWarningIcon { + margin-bottom: $euiSizeXS; + margin-left: $euiSizeS; +} + +.ruleDisabledQuestionIcon { + bottom: $euiSizeXS; + margin-left: $euiSizeXS; + position: relative; +} \ No newline at end of file diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx index 958511128de04..53f5e25530e98 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -17,6 +17,7 @@ import { AlertTypeModel, ValidationResult } from '../../../../types'; import { AlertExecutionStatusErrorReasons, ALERTS_FEATURE_ID, + parseDuration, } from '../../../../../../alerting/common'; import { useKibana } from '../../../../common/lib/kibana'; jest.mock('../../../../common/lib/kibana'); @@ -79,6 +80,7 @@ const alertTypeFromApi = { authorizedConsumers: { [ALERTS_FEATURE_ID]: { read: true, all: true }, }, + ruleTaskTimeout: '1m', }; ruleTypeRegistry.list.mockReturnValue([alertType]); actionTypeRegistry.list.mockReturnValue([]); @@ -170,6 +172,7 @@ describe('alerts_list component with items', () => { mutedInstanceIds: [], executionStatus: { status: 'active', + lastDuration: 500, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, @@ -192,6 +195,7 @@ describe('alerts_list component with items', () => { mutedInstanceIds: [], executionStatus: { status: 'ok', + lastDuration: 61000, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, @@ -214,6 +218,7 @@ describe('alerts_list component with items', () => { mutedInstanceIds: [], executionStatus: { status: 'pending', + lastDuration: 30234, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, @@ -236,6 +241,7 @@ describe('alerts_list component with items', () => { mutedInstanceIds: [], executionStatus: { status: 'error', + lastDuration: 122000, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { reason: AlertExecutionStatusErrorReasons.Unknown, @@ -246,7 +252,7 @@ describe('alerts_list component with items', () => { { id: '5', name: 'test alert license error', - tags: ['tag1'], + tags: [], enabled: true, alertTypeId: 'test_alert_type', schedule: { interval: '5d' }, @@ -261,6 +267,7 @@ describe('alerts_list component with items', () => { mutedInstanceIds: [], executionStatus: { status: 'error', + lastDuration: 500, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { reason: AlertExecutionStatusErrorReasons.License, @@ -324,6 +331,53 @@ describe('alerts_list component with items', () => { await setup(); expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(mockedAlertsData.length); + + // Enabled switch column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-enabled"]').length + ).toEqual(mockedAlertsData.length); + + // Name and rule type column + const ruleNameColumns = wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-name"]'); + expect(ruleNameColumns.length).toEqual(mockedAlertsData.length); + mockedAlertsData.forEach((rule, index) => { + expect(ruleNameColumns.at(index).text()).toEqual(`Name${rule.name}${alertTypeFromApi.name}`); + }); + + // Tags column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-tagsPopover"]').length + ).toEqual(mockedAlertsData.length); + // only show tags popover if tags exist on rule + const tagsBadges = wrapper.find('EuiBadge[data-test-subj="ruleTagsBadge"]'); + expect(tagsBadges.length).toEqual( + mockedAlertsData.filter((data) => data.tags.length > 0).length + ); + + // Last run column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-lastExecutionDate"]').length + ).toEqual(mockedAlertsData.length); + + // Schedule interval column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-interval"]').length + ).toEqual(mockedAlertsData.length); + + // Duration column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-duration"]').length + ).toEqual(mockedAlertsData.length); + // show warning if duration is long + const durationWarningIcon = wrapper.find('EuiIconTip[data-test-subj="ruleDurationWarning"]'); + expect(durationWarningIcon.length).toEqual( + mockedAlertsData.filter( + (data) => + data.executionStatus.lastDuration > parseDuration(alertTypeFromApi.ruleTaskTimeout) + ).length + ); + + // Status column expect(wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-status"]').length).toEqual( mockedAlertsData.length ); @@ -331,7 +385,6 @@ describe('alerts_list component with items', () => { expect(wrapper.find('EuiHealth[data-test-subj="alertStatus-ok"]').length).toEqual(1); expect(wrapper.find('EuiHealth[data-test-subj="alertStatus-pending"]').length).toEqual(1); expect(wrapper.find('EuiHealth[data-test-subj="alertStatus-unknown"]').length).toEqual(0); - expect(wrapper.find('EuiHealth[data-test-subj="alertStatus-error"]').length).toEqual(2); expect(wrapper.find('[data-test-subj="alertStatus-error-tooltip"]').length).toEqual(2); expect( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 1daaf3b996126..91b1b14083ed2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -8,7 +8,8 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { i18n } from '@kbn/i18n'; -import { capitalize, sortBy } from 'lodash'; +import { capitalize, padStart, sortBy } from 'lodash'; +import moment from 'moment'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useEffect, useState } from 'react'; import { @@ -29,6 +30,10 @@ import { EuiToolTip, EuiTableSortingType, EuiButtonIcon, + EuiHorizontalRule, + EuiPopover, + EuiPopoverTitle, + EuiIcon, } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; @@ -66,6 +71,8 @@ import { AlertExecutionStatusValues, ALERTS_FEATURE_ID, AlertExecutionStatusErrorReasons, + formatDuration, + parseDuration, } from '../../../../../../alerting/common'; import { alertsStatusesTranslationsMapping, ALERT_STATUS_LICENSE_ERROR } from '../translations'; import { useKibana } from '../../../../common/lib/kibana'; @@ -114,6 +121,7 @@ export const AlertsList: React.FunctionComponent = () => { const [dismissAlertErrors, setDismissAlertErrors] = useState(false); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); const [currentRuleToEdit, setCurrentRuleToEdit] = useState(null); + const [tagPopoverOpenIndex, setTagPopoverOpenIndex] = useState(-1); const [sort, setSort] = useState['sort']>({ field: 'name', @@ -334,7 +342,7 @@ export const AlertsList: React.FunctionComponent = () => { 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.enabledTitle', { defaultMessage: 'Enabled' } ), - width: '90px', + width: '50px', render(_enabled: boolean | undefined, item: AlertTableItem) { return ( { const checkEnabledResult = checkAlertTypeEnabled(ruleType); const link = ( <> - { - history.push(routeToRuleDetails.replace(`:ruleId`, alert.id)); - }} - > - {name} - + + + + + { + history.push(routeToRuleDetails.replace(`:ruleId`, alert.id)); + }} + > + {name} + + + + {!checkEnabledResult.isEnabled && ( + + )} + + + + + + {alert.alertType} + + + ); - return checkEnabledResult.isEnabled ? ( - link - ) : ( + return ( <> {link} - + {alert.enabled && alert.muteAll && ( + + + + )} ); }, }, { - field: 'executionStatus.status', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle', - { defaultMessage: 'Status' } - ), - sortable: true, - truncateText: false, - width: '120px', - 'data-test-subj': 'alertsTableCell-status', - render: (_executionStatus: AlertExecutionStatus, item: AlertTableItem) => { - return renderAlertExecutionStatus(item.executionStatus, item); - }, - }, - { - field: 'alertType', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle', - { defaultMessage: 'Type' } - ), + field: 'tags', + name: '', sortable: false, - truncateText: true, - render: (_count: number, item: AlertTableItem) => ( - {item.alertType} - ), - 'data-test-subj': 'alertsTableCell-alertType', + width: '50px', + 'data-test-subj': 'alertsTableCell-tagsPopover', + render: (tags: string[], item: AlertTableItem) => { + return tags.length > 0 ? ( + setTagPopoverOpenIndex(item.index)} + onClickAriaLabel="Tags" + iconOnClick={() => setTagPopoverOpenIndex(item.index)} + iconOnClickAriaLabel="Tags" + > + {tags.length} + + } + anchorPosition="upCenter" + isOpen={tagPopoverOpenIndex === item.index} + closePopover={() => setTagPopoverOpenIndex(-1)} + > + Tags +
+ {tags.map((tag: string, index: number) => ( + + {tag} + + ))} + + ) : null; + }, }, { - field: 'tagsText', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.tagsText', - { defaultMessage: 'Tags' } - ), - sortable: false, - 'data-test-subj': 'alertsTableCell-tagsText', - render: (_count: number, item: AlertTableItem) => ( -
- {item.tagsText} -
- ), + field: 'executionStatus.lastExecutionDate', + name: 'Last run', + sortable: true, + width: '15%', + 'data-test-subj': 'alertsTableCell-lastExecutionDate', + render: (date: Date) => { + if (date) { + return ( + <> + + + {moment(date).format('MMM D, YYYY HH:mm:ssa')} + + + + {moment(date).fromNow()} + + + + + ); + } + }, }, { field: 'schedule.interval', width: '6%', name: i18n.translate( 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.scheduleTitle', - { defaultMessage: 'Runs every' } + { defaultMessage: 'Interval' } ), sortable: false, truncateText: false, 'data-test-subj': 'alertsTableCell-interval', + render: (interval: string) => formatDuration(interval), }, { - width: '9%', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTitle', - { defaultMessage: 'Actions' } + field: 'executionStatus.lastDuration', + width: '12%', + name: ( + + + Duration{' '} + + + ), - render: (item: AlertTableItem) => { + sortable: true, + truncateText: false, + 'data-test-subj': 'alertsTableCell-duration', + render: (value: number, item: AlertTableItem) => { + const ruleTypeTimeout: string | undefined = alertTypesState.data.get( + item.alertTypeId + )?.ruleTaskTimeout; + const ruleTypeTimeoutMillis: number | undefined = ruleTypeTimeout + ? parseDuration(ruleTypeTimeout) + : undefined; + const showDurationWarning: boolean = ruleTypeTimeoutMillis + ? value > ruleTypeTimeoutMillis + : false; + const duration = moment.duration(value); + const durationString = [duration.hours(), duration.minutes(), duration.seconds()] + .map((v: number) => padStart(`${v}`, 2, '0')) + .join(':'); + + // add millis + const millisString = padStart(`${duration.milliseconds()}`, 3, '0'); return ( - - {item.actionsCount} - -
- {item.muteAll ? ( - - - - ) : null} -
-
-
+ <> + {`${durationString}.${millisString}`} + {showDurationWarning && ( + + )} + ); }, - 'data-test-subj': 'alertsTableCell-actions', + }, + { + field: 'executionStatus.status', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle', + { defaultMessage: 'Status' } + ), + sortable: true, + truncateText: false, + width: '120px', + 'data-test-subj': 'alertsTableCell-status', + render: (_executionStatus: AlertExecutionStatus, item: AlertTableItem) => { + return renderAlertExecutionStatus(item.executionStatus, item); + }, }, { name: '', @@ -669,7 +777,7 @@ export const AlertsList: React.FunctionComponent = () => { - + {!dismissAlertErrors && alertsStatusesTotal.error > 0 ? ( @@ -679,9 +787,9 @@ export const AlertsList: React.FunctionComponent = () => { title={ } @@ -726,10 +834,10 @@ export const AlertsList: React.FunctionComponent = () => { @@ -737,46 +845,45 @@ export const AlertsList: React.FunctionComponent = () => { - + - + - {/* Large to remain consistent with ActionsList table spacing */} - + { setAlertsState({ ...alertsState, isLoading }); }} /> - + {loadedItems.length || isFilterApplied ? ( table ) : alertTypesState.isLoading || alertsState.isLoading ? ( @@ -958,10 +1065,10 @@ function convertAlertsToTableItems( ruleTypeIndex: RuleTypeIndex, canExecuteActions: boolean ) { - return alerts.map((alert) => ({ + return alerts.map((alert, index: number) => ({ ...alert, + index, actionsCount: alert.actions.length, - tagsText: alert.tags.join(', '), alertType: ruleTypeIndex.get(alert.alertTypeId)?.name ?? alert.alertTypeId, isEditable: hasAllPrivilege(alert, ruleTypeIndex.get(alert.alertTypeId)) && diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.test.tsx index 5a06b03311cbe..807fe65a561f8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.test.tsx @@ -75,7 +75,7 @@ describe('CollapsedItemActions', () => { lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, actionsCount: 1, - tagsText: 'tag1', + index: 0, alertType: 'Test Alert Type', isEditable: true, enabledInLicense: true, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/rule_enabled_switch.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/rule_enabled_switch.test.tsx index bfa760b65ed4e..da75faeda95e9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/rule_enabled_switch.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/rule_enabled_switch.test.tsx @@ -40,7 +40,7 @@ describe('RuleEnabledSwitch', () => { enabledInLicense: true, isEditable: false, notifyWhen: null, - tagsText: 'test', + index: 0, updatedAt: new Date('2020-08-20T19:23:38Z'), }, onAlertChanged: jest.fn(), @@ -84,7 +84,7 @@ describe('RuleEnabledSwitch', () => { enabledInLicense: true, isEditable: true, notifyWhen: null, - tagsText: 'test', + index: 0, updatedAt: new Date('2020-08-20T19:23:38Z'), }, }} diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index 2ef20f36b7ca9..a78d1d52de0bd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -197,6 +197,7 @@ export interface AlertType< | 'minimumLicenseRequired' | 'recoveryActionGroup' | 'defaultActionGroupId' + | 'ruleTaskTimeout' | 'defaultScheduleInterval' | 'minimumScheduleInterval' > { @@ -211,7 +212,7 @@ export type AlertUpdates = Omit; export interface AlertTableItem extends Alert { alertType: AlertType['name']; - tagsText: string; + index: number; actionsCount: number; isEditable: boolean; enabledInLicense: boolean; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts index f52f0977a630b..b070219410fd9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/rule_types.ts @@ -36,6 +36,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { name: 'Recovered', }, enabled_in_license: true, + rule_task_timeout: '5m', }; const expectedRestrictedNoOpType = { @@ -59,6 +60,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { minimum_license_required: 'basic', is_exportable: true, enabled_in_license: true, + rule_task_timeout: '5m', }; describe('rule_types', () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts index 86a0e269b26d6..77638ed90fbe4 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/rule_types.ts @@ -44,6 +44,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { minimum_license_required: 'basic', is_exportable: true, enabled_in_license: true, + rule_task_timeout: '5m', }); expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); }); @@ -129,6 +130,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { minimumLicenseRequired: 'basic', isExportable: true, enabledInLicense: true, + ruleTaskTimeout: '5m', }); expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture'); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts index 3f36032523e8b..dede481669664 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts @@ -88,9 +88,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); expect(searchResults).to.have.length(3); - expect(searchResults[0].name).to.eql('a'); - expect(searchResults[1].name).to.eql('b'); - expect(searchResults[2].name).to.eql('c'); + // rule list shows name and rule type id + expect(searchResults[0].name).to.eql('aTest: Noop'); + expect(searchResults[1].name).to.eql('bTest: Noop'); + expect(searchResults[2].name).to.eql('cTest: Noop'); }); it('should search for alert', async () => { @@ -99,67 +100,54 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResults).to.eql([ - { - name: createdAlert.name, - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - ]); + expect(searchResults.length).to.equal(1); + expect(searchResults[0].name).to.equal(`${createdAlert.name}Test: Noop`); + expect(searchResults[0].interval).to.equal('1 min'); + expect(searchResults[0].tags).to.equal('2'); + expect(searchResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); it('should update alert list on the search clear button click', async () => { await createAlert({ name: 'b' }); - await createAlert({ name: 'c' }); + await createAlert({ name: 'c', tags: [] }); await refreshAlertsList(); await pageObjects.triggersActionsUI.searchAlerts('b'); const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResults).to.eql([ - { - name: 'b', - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - ]); + expect(searchResults.length).to.equal(1); + expect(searchResults[0].name).to.equal('bTest: Noop'); + expect(searchResults[0].interval).to.equal('1 min'); + expect(searchResults[0].tags).to.equal('2'); + expect(searchResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); + const searchClearButton = await find.byCssSelector('.euiFormControlLayoutClearButton'); await searchClearButton.click(); await find.byCssSelector( '.euiBasicTable[data-test-subj="alertsList"]:not(.euiBasicTable-loading)' ); const searchResultsAfterClear = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResultsAfterClear).to.eql([ - { - name: 'b', - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - { - name: 'c', - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - ]); + expect(searchResultsAfterClear.length).to.equal(2); + expect(searchResultsAfterClear[0].name).to.equal('bTest: Noop'); + expect(searchResultsAfterClear[0].interval).to.equal('1 min'); + expect(searchResultsAfterClear[0].tags).to.equal('2'); + expect(searchResultsAfterClear[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); + expect(searchResultsAfterClear[1].name).to.equal('cTest: Noop'); + expect(searchResultsAfterClear[1].interval).to.equal('1 min'); + expect(searchResultsAfterClear[1].tags).to.equal(''); + expect(searchResultsAfterClear[1].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); it('should search for tags', async () => { - const createdAlert = await createAlert(); + const createdAlert = await createAlert({ tags: ['tag', 'tagtag', 'taggity tag'] }); await refreshAlertsList(); - await pageObjects.triggersActionsUI.searchAlerts(`${createdAlert.name} foo`); + await pageObjects.triggersActionsUI.searchAlerts(`${createdAlert.name} tag`); const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResults).to.eql([ - { - name: createdAlert.name, - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - ]); + expect(searchResults.length).to.equal(1); + expect(searchResults[0].name).to.equal(`${createdAlert.name}Test: Noop`); + expect(searchResults[0].interval).to.equal('1 min'); + expect(searchResults[0].tags).to.equal('3'); + expect(searchResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); it('should display an empty list when search did not return any alerts', async () => { @@ -385,15 +373,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.try(async () => { const filterErrorOnlyResults = await pageObjects.triggersActionsUI.getAlertsListWithStatus(); - expect(filterErrorOnlyResults).to.eql([ - { - name: failingAlert.name, - tagsText: 'foo, bar', - alertType: 'Test: Failing', - interval: '30s', - status: 'Error', - }, - ]); + expect(filterErrorOnlyResults.length).to.equal(1); + expect(filterErrorOnlyResults[0].name).to.equal(`${failingAlert.name}Test: Failing`); + expect(filterErrorOnlyResults[0].interval).to.equal('30 sec'); + expect(filterErrorOnlyResults[0].status).to.equal('Error'); + expect(filterErrorOnlyResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); }); @@ -402,15 +386,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.try(async () => { await refreshAlertsList(); const refreshResults = await pageObjects.triggersActionsUI.getAlertsListWithStatus(); - expect(refreshResults).to.eql([ - { - name: createdAlert.name, - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - status: 'Ok', - }, - ]); + expect(refreshResults.length).to.equal(1); + expect(refreshResults[0].name).to.equal(`${createdAlert.name}Test: Noop`); + expect(refreshResults[0].interval).to.equal('1 min'); + expect(refreshResults[0].status).to.equal('Ok'); + expect(refreshResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); const alertsErrorBannerWhenNoErrors = await find.allByCssSelector( @@ -451,14 +431,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.try(async () => { const filterFailingAlertOnlyResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(filterFailingAlertOnlyResults).to.eql([ - { - name: failingAlert.name, - tagsText: 'foo, bar', - alertType: 'Test: Failing', - interval: '30s', - }, - ]); + expect(filterFailingAlertOnlyResults.length).to.equal(1); + expect(filterFailingAlertOnlyResults[0].name).to.equal(`${failingAlert.name}Test: Failing`); + expect(filterFailingAlertOnlyResults[0].interval).to.equal('30 sec'); + expect(filterFailingAlertOnlyResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); }); @@ -480,14 +456,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.try(async () => { const filterWithSlackOnlyResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(filterWithSlackOnlyResults).to.eql([ - { - name: noopAlertWithAction.name, - tagsText: 'foo, bar', - alertType: 'Test: Noop', - interval: '1m', - }, - ]); + expect(filterWithSlackOnlyResults.length).to.equal(1); + expect(filterWithSlackOnlyResults[0].name).to.equal( + `${noopAlertWithAction.name}Test: Noop` + ); + expect(filterWithSlackOnlyResults[0].interval).to.equal('1 min'); + expect(filterWithSlackOnlyResults[0].duration).to.match(/\d{2}:\d{2}:\d{2}.\d{3}/); }); }); }); 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 890315698f74c..a49873c6d47b5 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 @@ -22,18 +22,18 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) function getRowItemData(row: CustomCheerio, $: CustomCheerioStatic) { return { name: $(row).findTestSubject('alertsTableCell-name').find('.euiTableCellContent').text(), - tagsText: $(row) - .findTestSubject('alertsTableCell-tagsText') - .find('.euiTableCellContent') - .text(), - alertType: $(row) - .findTestSubject('alertsTableCell-alertType') + duration: $(row) + .findTestSubject('alertsTableCell-duration') .find('.euiTableCellContent') .text(), interval: $(row) .findTestSubject('alertsTableCell-interval') .find('.euiTableCellContent') .text(), + tags: $(row) + .findTestSubject('alertsTableCell-tagsPopover') + .find('.euiTableCellContent') + .text(), }; } From 243c2133aff98b21aef7e12ee65d50539dded4db Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Mon, 11 Oct 2021 21:35:00 -0500 Subject: [PATCH 31/73] [nit][pre-req] Strongly-type Shipper and Category (#114412) --- .../custom_integrations/common/index.ts | 61 ++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/plugins/custom_integrations/common/index.ts b/src/plugins/custom_integrations/common/index.ts index e2408d3124604..9af7c4ccd4633 100755 --- a/src/plugins/custom_integrations/common/index.ts +++ b/src/plugins/custom_integrations/common/index.ts @@ -9,13 +9,11 @@ export const PLUGIN_ID = 'customIntegrations'; export const PLUGIN_NAME = 'customIntegrations'; -export interface IntegrationCategoryCount { - count: number; - id: IntegrationCategory; -} - +/** + * A map of category names and their corresponding titles. + */ +// TODO: consider i18n export const INTEGRATION_CATEGORY_DISPLAY = { - // Known EPR aws: 'AWS', azure: 'Azure', cloud: 'Cloud', @@ -49,13 +47,62 @@ export const INTEGRATION_CATEGORY_DISPLAY = { updates_available: 'Updates available', }; +/** + * A category applicable to an Integration. + */ export type IntegrationCategory = keyof typeof INTEGRATION_CATEGORY_DISPLAY; +/** + * The list of all available categories. + */ +// This `as` is necessary, as Object.keys cannot be strongly typed. +// see: https://github.com/Microsoft/TypeScript/issues/12870 +export const category = Object.keys(INTEGRATION_CATEGORY_DISPLAY) as IntegrationCategory[]; + +/** + * An object containing the id of an `IntegrationCategory` and the count of all Integrations in that category. + */ +export interface IntegrationCategoryCount { + count: number; + id: IntegrationCategory; +} + +/** + * A map of shipper names and their corresponding titles. + */ +// TODO: consider i18n +export const SHIPPER_DISPLAY = { + beats: 'Beats', + language_clients: 'Language clients', + other: 'Other', + sample_data: 'Sample data', + tests: 'Tests', + tutorial: 'Tutorials', +}; + +/** + * A shipper-- an internal or external system capable of storing data in ES/Kibana-- applicable to an Integration. + */ +export type Shipper = keyof typeof SHIPPER_DISPLAY; + +/** + * The list of all known shippers. + */ +// This `as` is necessary, as Object.keys cannot be strongly typed. +// see: https://github.com/Microsoft/TypeScript/issues/12870 +export const shipper = Object.keys(SHIPPER_DISPLAY) as Shipper[]; + +/** + * An icon representing an Integration. + */ export interface CustomIntegrationIcon { src: string; type: 'eui' | 'svg'; } +/** + * A definition of a dataintegration, which can be registered with Kibana. + */ export interface CustomIntegration { id: string; title: string; @@ -65,7 +112,7 @@ export interface CustomIntegration { isBeta: boolean; icons: CustomIntegrationIcon[]; categories: IntegrationCategory[]; - shipper: string; + shipper: Shipper; eprOverlap?: string; // name of the equivalent Elastic Agent integration in EPR. e.g. a beat module can correspond to an EPR-package, or an APM-tutorial. When completed, Integrations-UX can preferentially show the EPR-package, rather than the custom-integration } From 7c087fea8226ab8bee96cb44e1a5111701b4a904 Mon Sep 17 00:00:00 2001 From: Spencer Date: Mon, 11 Oct 2021 23:01:02 -0500 Subject: [PATCH 32/73] [ci-stats] support sending meta with metrics (#114198) * [ci-stats] support sending meta with metrics * update kbn/pm dist * improve comments stat * update kbn/pm dist Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../ci_stats_reporter/ci_stats_reporter.ts | 51 ++++++++++++++++--- packages/kbn-pm/dist/index.js | 25 +++++++-- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts index fe48ce99e6857..05f54e8d38c8c 100644 --- a/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts @@ -22,24 +22,43 @@ import { parseConfig, Config } from './ci_stats_config'; const BASE_URL = 'https://ci-stats.kibana.dev'; export interface CiStatsMetric { + /** Top-level categorization for the metric, e.g. "page load bundle size" */ group: string; + /** Specific sub-set of the "group", e.g. "dashboard" */ id: string; + /** integer value recorded as the value of this metric */ value: number; + /** optional limit which will generate an error on PRs when the metric exceeds the limit */ limit?: number; + /** + * path, relative to the repo, where the config file contianing limits + * is kept. Linked from PR comments instructing contributors how to fix + * their PRs. + */ limitConfigPath?: string; + /** Arbitrary key-value pairs which can be used for additional filtering/reporting */ + meta?: CiStatsMetadata; } -export interface CiStatsTimingMetadata { +export interface CiStatsMetadata { + /** + * Arbitrary key-value pairs which can be attached to CiStatsTiming and CiStatsMetric + * objects stored in the ci-stats service + */ [key: string]: string | string[] | number | boolean | undefined; } export interface CiStatsTiming { + /** Top-level categorization for the timing, e.g. "scripts/foo", process type, etc. */ group: string; + /** Specific timing (witin the "group" being tracked) e.g. "total" */ id: string; + /** time in milliseconds which should be recorded */ ms: number; - meta?: CiStatsTimingMetadata; + /** hash of key-value pairs which will be stored with the timing for additional filtering and reporting */ + meta?: CiStatsMetadata; } -export interface ReqOptions { +interface ReqOptions { auth: boolean; path: string; body: any; @@ -54,17 +73,34 @@ export interface TimingsOptions { /** value of data/uuid, automatically loaded if not specified */ kibanaUuid?: string | null; } + +export interface MetricsOptions { + /** Default metadata to add to each metric */ + defaultMeta?: CiStatsMetadata; +} export class CiStatsReporter { + /** + * Create a CiStatsReporter by inspecting the ENV for the necessary config + */ static fromEnv(log: ToolingLog) { return new CiStatsReporter(parseConfig(log), log); } constructor(private config: Config | undefined, private log: ToolingLog) {} + /** + * Determine if CI_STATS is explicitly disabled by the environment. To determine + * if the CiStatsReporter has enough information in the environment to send metrics + * for builds use #hasBuildConfig(). + */ isEnabled() { return process.env.CI_STATS_DISABLED !== 'true'; } + /** + * Determines if the CiStatsReporter is disabled by the environment, or properly + * configured and able to send stats + */ hasBuildConfig() { return this.isEnabled() && !!this.config?.apiToken && !!this.config?.buildId; } @@ -103,7 +139,7 @@ export class CiStatsReporter { const memUsage = process.memoryUsage(); const isElasticCommitter = email && email.endsWith('@elastic.co') ? true : false; - const defaultMetadata = { + const defaultMeta = { kibanaUuid, isElasticCommitter, committerHash: email @@ -127,7 +163,7 @@ export class CiStatsReporter { totalMem: Os.totalmem(), }; - this.log.debug('CIStatsReporter committerHash: %s', defaultMetadata.committerHash); + this.log.debug('CIStatsReporter committerHash: %s', defaultMeta.committerHash); return await this.req({ auth: !!buildId, @@ -135,8 +171,8 @@ export class CiStatsReporter { body: { buildId, upstreamBranch, + defaultMeta, timings, - defaultMetadata, }, bodyDesc: timings.length === 1 ? `${timings.length} timing` : `${timings.length} timings`, }); @@ -146,7 +182,7 @@ export class CiStatsReporter { * Report metrics data to the ci-stats service. If running outside of CI this method * does nothing as metrics can only be reported when associated with a specific CI build. */ - async metrics(metrics: CiStatsMetric[]) { + async metrics(metrics: CiStatsMetric[], options?: MetricsOptions) { if (!this.hasBuildConfig()) { return; } @@ -162,6 +198,7 @@ export class CiStatsReporter { path: '/v1/metrics', body: { buildId, + defaultMeta: options?.defaultMeta, metrics, }, bodyDesc: `metrics: ${metrics diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index a231fe21ea838..3c0e3fa94be02 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -9010,6 +9010,9 @@ var _ci_stats_config = __webpack_require__(218); const BASE_URL = 'https://ci-stats.kibana.dev'; class CiStatsReporter { + /** + * Create a CiStatsReporter by inspecting the ENV for the necessary config + */ static fromEnv(log) { return new CiStatsReporter((0, _ci_stats_config.parseConfig)(log), log); } @@ -9018,10 +9021,21 @@ class CiStatsReporter { this.config = config; this.log = log; } + /** + * Determine if CI_STATS is explicitly disabled by the environment. To determine + * if the CiStatsReporter has enough information in the environment to send metrics + * for builds use #hasBuildConfig(). + */ + isEnabled() { return process.env.CI_STATS_DISABLED !== 'true'; } + /** + * Determines if the CiStatsReporter is disabled by the environment, or properly + * configured and able to send stats + */ + hasBuildConfig() { var _this$config, _this$config2; @@ -9069,7 +9083,7 @@ class CiStatsReporter { const memUsage = process.memoryUsage(); const isElasticCommitter = email && email.endsWith('@elastic.co') ? true : false; - const defaultMetadata = { + const defaultMeta = { kibanaUuid, isElasticCommitter, committerHash: email ? _crypto.default.createHash('sha256').update(email).digest('hex').substring(0, 20) : undefined, @@ -9090,15 +9104,15 @@ class CiStatsReporter { osRelease: _os.default.release(), totalMem: _os.default.totalmem() }; - this.log.debug('CIStatsReporter committerHash: %s', defaultMetadata.committerHash); + this.log.debug('CIStatsReporter committerHash: %s', defaultMeta.committerHash); return await this.req({ auth: !!buildId, path: '/v1/timings', body: { buildId, upstreamBranch, - timings, - defaultMetadata + defaultMeta, + timings }, bodyDesc: timings.length === 1 ? `${timings.length} timing` : `${timings.length} timings` }); @@ -9109,7 +9123,7 @@ class CiStatsReporter { */ - async metrics(metrics) { + async metrics(metrics, options) { var _this$config4; if (!this.hasBuildConfig()) { @@ -9127,6 +9141,7 @@ class CiStatsReporter { path: '/v1/metrics', body: { buildId, + defaultMeta: options === null || options === void 0 ? void 0 : options.defaultMeta, metrics }, bodyDesc: `metrics: ${metrics.map(({ From ab5ecc4e13a92c28980deabdae579b69c252dffe Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Tue, 12 Oct 2021 00:07:16 -0500 Subject: [PATCH 33/73] [nit][pre-req] Split EPM Home into components (#114431) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/package_list_grid.stories.tsx | 4 +- .../epm/components/package_list_grid.tsx | 12 +- .../epm/screens/home/available_packages.tsx | 212 +++++++++++ .../epm/screens/home/category_facets.tsx | 16 +- .../sections/epm/screens/home/index.tsx | 360 +----------------- .../epm/screens/home/installed_packages.tsx | 159 ++++++++ 6 files changed, 408 insertions(+), 355 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx create mode 100644 x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx index c355eb8607f45..e4bd1da842867 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import type { ListProps } from './package_list_grid'; +import type { Props } from './package_list_grid'; import { PackageListGrid } from './package_list_grid'; export default { @@ -17,7 +17,7 @@ export default { title: 'Sections/EPM/Package List Grid', }; -type Args = Pick; +type Args = Pick; const args: Args = { title: 'Installed integrations', diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx index 109f7500f160b..1cffd5292b6a2 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx @@ -14,7 +14,6 @@ import { EuiLink, EuiSpacer, EuiTitle, - // @ts-ignore EuiSearchBar, EuiText, } from '@elastic/eui'; @@ -29,7 +28,7 @@ import type { IntegrationCardItem } from '../../../../../../common/types/models' import { PackageCard } from './package_card'; -export interface ListProps { +export interface Props { isLoading?: boolean; controls?: ReactNode; title: string; @@ -51,7 +50,7 @@ export function PackageListGrid({ setSelectedCategory, showMissingIntegrationMessage = false, callout, -}: ListProps) { +}: Props) { const [searchTerm, setSearchTerm] = useState(initialSearch || ''); const localSearchRef = useLocalSearch(list); @@ -107,7 +106,12 @@ export function PackageListGrid({ }} onChange={onQueryChange} /> - {callout ? callout : null} + {callout ? ( + <> + + {callout} + + ) : null} {gridContent} {showMissingIntegrationMessage && ( diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx new file mode 100644 index 0000000000000..8aef9121bf67d --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx @@ -0,0 +1,212 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useMemo } from 'react'; +import { useLocation, useHistory, useParams } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; + +import { pagePathGetters } from '../../../../constants'; +import { + useGetCategories, + useGetPackages, + useBreadcrumbs, + useGetAppendCustomIntegrations, + useGetReplacementCustomIntegrations, + useLink, +} from '../../../../hooks'; +import { doesPackageHaveIntegrations } from '../../../../services'; +import type { PackageList } from '../../../../types'; +import { PackageListGrid } from '../../components/package_list_grid'; + +import type { CustomIntegration } from '../../../../../../../../../../src/plugins/custom_integrations/common'; + +import type { PackageListItem } from '../../../../types'; + +import type { IntegrationCategory } from '../../../../../../../../../../src/plugins/custom_integrations/common'; + +import { useMergeEprPackagesWithReplacements } from '../../../../../../hooks/use_merge_epr_with_replacements'; + +import { mergeAndReplaceCategoryCounts } from './util'; +import { CategoryFacets } from './category_facets'; +import type { CategoryFacet } from './category_facets'; + +import type { CategoryParams } from '.'; +import { getParams, categoryExists, mapToCard } from '.'; + +// Packages can export multiple integrations, aka `policy_templates` +// In the case where packages ship >1 `policy_templates`, we flatten out the +// list of packages by bringing all integrations to top-level so that +// each integration is displayed as its own tile +const packageListToIntegrationsList = (packages: PackageList): PackageList => { + return packages.reduce((acc: PackageList, pkg) => { + const { policy_templates: policyTemplates = [], ...restOfPackage } = pkg; + return [ + ...acc, + restOfPackage, + ...(doesPackageHaveIntegrations(pkg) + ? policyTemplates.map((integration) => { + const { name, title, description, icons } = integration; + return { + ...restOfPackage, + id: `${restOfPackage}-${name}`, + integration: name, + title, + description, + icons: icons || restOfPackage.icons, + }; + }) + : []), + ]; + }, []); +}; + +const title = i18n.translate('xpack.fleet.epmList.allTitle', { + defaultMessage: 'Browse by category', +}); + +// TODO: clintandrewhall - this component is hard to test due to the hooks, particularly those that use `http` +// or `location` to load data. Ideally, we'll split this into "connected" and "pure" components. +export const AvailablePackages: React.FC = memo(() => { + useBreadcrumbs('integrations_all'); + + const { selectedCategory, searchParam } = getParams( + useParams(), + useLocation().search + ); + + const history = useHistory(); + + const { getHref, getAbsolutePath } = useLink(); + + function setSelectedCategory(categoryId: string) { + const url = pagePathGetters.integrations_all({ + category: categoryId, + searchTerm: searchParam, + })[1]; + history.push(url); + } + + function setSearchTerm(search: string) { + // Use .replace so the browser's back button is not tied to single keystroke + history.replace( + pagePathGetters.integrations_all({ category: selectedCategory, searchTerm: search })[1] + ); + } + + const { data: allCategoryPackagesRes, isLoading: isLoadingAllPackages } = useGetPackages({ + category: '', + }); + + const { data: categoryPackagesRes, isLoading: isLoadingCategoryPackages } = useGetPackages({ + category: selectedCategory, + }); + + const { data: categoriesRes, isLoading: isLoadingCategories } = useGetCategories({ + include_policy_templates: true, + }); + + const eprPackages = useMemo( + () => packageListToIntegrationsList(categoryPackagesRes?.response || []), + [categoryPackagesRes] + ); + + const allEprPackages = useMemo( + () => packageListToIntegrationsList(allCategoryPackagesRes?.response || []), + [allCategoryPackagesRes] + ); + + const { value: replacementCustomIntegrations } = useGetReplacementCustomIntegrations(); + + const mergedEprPackages: Array = + useMergeEprPackagesWithReplacements( + eprPackages || [], + replacementCustomIntegrations || [], + selectedCategory as IntegrationCategory + ); + + const { loading: isLoadingAppendCustomIntegrations, value: appendCustomIntegrations } = + useGetAppendCustomIntegrations(); + + const filteredAddableIntegrations = appendCustomIntegrations + ? appendCustomIntegrations.filter((integration: CustomIntegration) => { + if (!selectedCategory) { + return true; + } + return integration.categories.indexOf(selectedCategory as IntegrationCategory) >= 0; + }) + : []; + + const eprAndCustomPackages: Array = [ + ...mergedEprPackages, + ...filteredAddableIntegrations, + ]; + + eprAndCustomPackages.sort((a, b) => { + return a.title.localeCompare(b.title); + }); + + const categories = useMemo(() => { + const eprAndCustomCategories: CategoryFacet[] = + isLoadingCategories || + isLoadingAppendCustomIntegrations || + !appendCustomIntegrations || + !categoriesRes + ? [] + : mergeAndReplaceCategoryCounts( + categoriesRes.response as CategoryFacet[], + appendCustomIntegrations + ); + + return [ + { + id: '', + count: (allEprPackages?.length || 0) + (appendCustomIntegrations?.length || 0), + }, + ...(eprAndCustomCategories ? eprAndCustomCategories : []), + ] as CategoryFacet[]; + }, [ + allEprPackages?.length, + appendCustomIntegrations, + categoriesRes, + isLoadingAppendCustomIntegrations, + isLoadingCategories, + ]); + + if (!isLoadingCategories && !categoryExists(selectedCategory, categories)) { + history.replace(pagePathGetters.integrations_all({ category: '', searchTerm: searchParam })[1]); + return null; + } + + const controls = categories ? ( + { + setSelectedCategory(id); + }} + /> + ) : null; + + const cards = eprAndCustomPackages.map((item) => { + return mapToCard(getAbsolutePath, getHref, item); + }); + + return ( + + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx index d60ccd93b8db1..3eba17d6627a1 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx @@ -21,19 +21,21 @@ interface ALL_CATEGORY { export type CategoryFacet = IntegrationCategoryCount | ALL_CATEGORY; +export interface Props { + showCounts: boolean; + isLoading?: boolean; + categories: CategoryFacet[]; + selectedCategory: string; + onCategoryChange: (category: CategoryFacet) => unknown; +} + export function CategoryFacets({ showCounts, isLoading, categories, selectedCategory, onCategoryChange, -}: { - showCounts: boolean; - isLoading?: boolean; - categories: CategoryFacet[]; - selectedCategory: string; - onCategoryChange: (category: CategoryFacet) => unknown; -}) { +}: Props) { const controls = ( {isLoading ? ( diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx index 06cf85699bf67..bbebf9e90b16c 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx @@ -5,34 +5,12 @@ * 2.0. */ -import React, { memo, useMemo, Fragment } from 'react'; -import { Switch, Route, useLocation, useHistory, useParams } from 'react-router-dom'; -import semverLt from 'semver/functions/lt'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; +import React, { memo } from 'react'; +import { Switch, Route } from 'react-router-dom'; -import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; - -import { installationStatuses } from '../../../../../../../common/constants'; import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants'; -import { - INTEGRATIONS_ROUTING_PATHS, - INTEGRATIONS_SEARCH_QUERYPARAM, - pagePathGetters, -} from '../../../../constants'; -import { - useGetCategories, - useGetPackages, - useBreadcrumbs, - useGetAppendCustomIntegrations, - useGetReplacementCustomIntegrations, - useLink, - useStartServices, -} from '../../../../hooks'; -import { doesPackageHaveIntegrations } from '../../../../services'; +import { INTEGRATIONS_ROUTING_PATHS, INTEGRATIONS_SEARCH_QUERYPARAM } from '../../../../constants'; import { DefaultLayout } from '../../../../layouts'; -import type { PackageList } from '../../../../types'; -import { PackageListGrid } from '../../components/package_list_grid'; import type { CustomIntegration } from '../../../../../../../../../../src/plugins/custom_integrations/common'; @@ -40,47 +18,47 @@ import type { PackageListItem } from '../../../../types'; import type { IntegrationCardItem } from '../../../../../../../common/types/models'; -import type { IntegrationCategory } from '../../../../../../../../../../src/plugins/custom_integrations/common'; - -import { useMergeEprPackagesWithReplacements } from '../../../../../../hooks/use_merge_epr_with_replacements'; - -import { mergeAndReplaceCategoryCounts } from './util'; -import { CategoryFacets } from './category_facets'; import type { CategoryFacet } from './category_facets'; +import { InstalledPackages } from './installed_packages'; +import { AvailablePackages } from './available_packages'; export interface CategoryParams { category?: string; } -function getParams(params: CategoryParams, search: string) { +export const getParams = (params: CategoryParams, search: string) => { const { category } = params; const selectedCategory = category || ''; const queryParams = new URLSearchParams(search); const searchParam = queryParams.get(INTEGRATIONS_SEARCH_QUERYPARAM) || ''; return { selectedCategory, searchParam }; -} +}; -function categoryExists(category: string, categories: CategoryFacet[]) { +export const categoryExists = (category: string, categories: CategoryFacet[]) => { return categories.some((c) => c.id === category); -} +}; -function mapToCard( +export const mapToCard = ( getAbsolutePath: (p: string) => string, getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => string, item: CustomIntegration | PackageListItem -): IntegrationCardItem { +): IntegrationCardItem => { let uiInternalPathUrl; + if (item.type === 'ui_link') { uiInternalPathUrl = getAbsolutePath(item.uiInternalPath); } else { let urlVersion = item.version; + if ('savedObject' in item) { urlVersion = item.savedObject.attributes.version || item.version; } + const url = getHref('integration_details_overview', { pkgkey: `${item.name}-${urlVersion}`, ...(item.integration ? { integration: item.integration } : {}), }); + uiInternalPathUrl = url; } @@ -88,14 +66,14 @@ function mapToCard( id: `${item.type === 'ui_link' ? 'ui_link' : 'epr'}-${item.id}`, description: item.description, icons: !item.icons || !item.icons.length ? [] : item.icons, + title: item.title, + url: uiInternalPathUrl, integration: 'integration' in item ? item.integration || '' : '', name: 'name' in item ? item.name || '' : '', - title: item.title, version: 'version' in item ? item.version || '' : '', release: 'release' in item ? item.release : undefined, - url: uiInternalPathUrl, }; -} +}; export const EPMHomePage: React.FC = memo(() => { return ( @@ -113,305 +91,3 @@ export const EPMHomePage: React.FC = memo(() => { ); }); - -// Packages can export multiple integrations, aka `policy_templates` -// In the case where packages ship >1 `policy_templates`, we flatten out the -// list of packages by bringing all integrations to top-level so that -// each integration is displayed as its own tile -const packageListToIntegrationsList = (packages: PackageList): PackageList => { - return packages.reduce((acc: PackageList, pkg) => { - const { policy_templates: policyTemplates = [], ...restOfPackage } = pkg; - return [ - ...acc, - restOfPackage, - ...(doesPackageHaveIntegrations(pkg) - ? policyTemplates.map((integration) => { - const { name, title, description, icons } = integration; - return { - ...restOfPackage, - id: `${restOfPackage}-${name}`, - integration: name, - title, - description, - icons: icons || restOfPackage.icons, - }; - }) - : []), - ]; - }, []); -}; - -const InstalledPackages: React.FC = memo(() => { - useBreadcrumbs('integrations_installed'); - const { data: allPackages, isLoading: isLoadingPackages } = useGetPackages({ - experimental: true, - }); - const { getHref, getAbsolutePath } = useLink(); - const { docLinks } = useStartServices(); - - const { selectedCategory, searchParam } = getParams( - useParams(), - useLocation().search - ); - const history = useHistory(); - function setSelectedCategory(categoryId: string) { - const url = pagePathGetters.integrations_installed({ - category: categoryId, - searchTerm: searchParam, - })[1]; - history.push(url); - } - function setSearchTerm(search: string) { - // Use .replace so the browser's back button is not tied to single keystroke - history.replace( - pagePathGetters.integrations_installed({ - category: selectedCategory, - searchTerm: search, - })[1] - ); - } - - const allInstalledPackages = useMemo( - () => - (allPackages?.response || []).filter((pkg) => pkg.status === installationStatuses.Installed), - [allPackages?.response] - ); - - const updatablePackages = useMemo( - () => - allInstalledPackages.filter( - (item) => - 'savedObject' in item && semverLt(item.savedObject.attributes.version, item.version) - ), - [allInstalledPackages] - ); - - const title = useMemo( - () => - i18n.translate('xpack.fleet.epmList.installedTitle', { - defaultMessage: 'Installed integrations', - }), - [] - ); - - const categories: CategoryFacet[] = useMemo( - () => [ - { - id: '', - count: allInstalledPackages.length, - }, - { - id: 'updates_available', - count: updatablePackages.length, - }, - ], - [allInstalledPackages.length, updatablePackages.length] - ); - - if (!categoryExists(selectedCategory, categories)) { - history.replace( - pagePathGetters.integrations_installed({ category: '', searchTerm: searchParam })[1] - ); - return null; - } - - const controls = ( - setSelectedCategory(id)} - /> - ); - - const cards = ( - selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages - ).map((item) => { - return mapToCard(getAbsolutePath, getHref, item); - }); - - const link = ( - - {i18n.translate('xpack.fleet.epmList.availableCalloutBlogText', { - defaultMessage: 'announcement blog post', - })} - - ); - const calloutMessage = ( - - ); - - const callout = - selectedCategory === 'updates_available' ? null : ( - - - -

{calloutMessage}

-
-
- ); - - return ( - - ); -}); - -const AvailablePackages: React.FC = memo(() => { - useBreadcrumbs('integrations_all'); - const { selectedCategory, searchParam } = getParams( - useParams(), - useLocation().search - ); - const history = useHistory(); - const { getHref, getAbsolutePath } = useLink(); - - function setSelectedCategory(categoryId: string) { - const url = pagePathGetters.integrations_all({ - category: categoryId, - searchTerm: searchParam, - })[1]; - history.push(url); - } - function setSearchTerm(search: string) { - // Use .replace so the browser's back button is not tied to single keystroke - history.replace( - pagePathGetters.integrations_all({ category: selectedCategory, searchTerm: search })[1] - ); - } - - const { data: allCategoryPackagesRes, isLoading: isLoadingAllPackages } = useGetPackages({ - category: '', - }); - const { data: categoryPackagesRes, isLoading: isLoadingCategoryPackages } = useGetPackages({ - category: selectedCategory, - }); - const { data: categoriesRes, isLoading: isLoadingCategories } = useGetCategories({ - include_policy_templates: true, - }); - - const eprPackages = useMemo( - () => packageListToIntegrationsList(categoryPackagesRes?.response || []), - [categoryPackagesRes] - ); - - const allEprPackages = useMemo( - () => packageListToIntegrationsList(allCategoryPackagesRes?.response || []), - [allCategoryPackagesRes] - ); - - const { value: replacementCustomIntegrations } = useGetReplacementCustomIntegrations(); - - const mergedEprPackages: Array = - useMergeEprPackagesWithReplacements( - eprPackages || [], - replacementCustomIntegrations || [], - selectedCategory as IntegrationCategory - ); - - const { loading: isLoadingAppendCustomIntegrations, value: appendCustomIntegrations } = - useGetAppendCustomIntegrations(); - const filteredAddableIntegrations = appendCustomIntegrations - ? appendCustomIntegrations.filter((integration: CustomIntegration) => { - if (!selectedCategory) { - return true; - } - return integration.categories.indexOf(selectedCategory as IntegrationCategory) >= 0; - }) - : []; - - const title = useMemo( - () => - i18n.translate('xpack.fleet.epmList.allTitle', { - defaultMessage: 'Browse by category', - }), - [] - ); - - const eprAndCustomPackages: Array = [ - ...mergedEprPackages, - ...filteredAddableIntegrations, - ]; - eprAndCustomPackages.sort((a, b) => { - return a.title.localeCompare(b.title); - }); - - const categories = useMemo(() => { - const eprAndCustomCategories: CategoryFacet[] = - isLoadingCategories || - isLoadingAppendCustomIntegrations || - !appendCustomIntegrations || - !categoriesRes - ? [] - : mergeAndReplaceCategoryCounts( - categoriesRes.response as CategoryFacet[], - appendCustomIntegrations - ); - return [ - { - id: '', - count: (allEprPackages?.length || 0) + (appendCustomIntegrations?.length || 0), - }, - ...(eprAndCustomCategories ? eprAndCustomCategories : []), - ] as CategoryFacet[]; - }, [ - allEprPackages?.length, - appendCustomIntegrations, - categoriesRes, - isLoadingAppendCustomIntegrations, - isLoadingCategories, - ]); - - if (!isLoadingCategories && !categoryExists(selectedCategory, categories)) { - history.replace(pagePathGetters.integrations_all({ category: '', searchTerm: searchParam })[1]); - return null; - } - - const controls = categories ? ( - { - setSelectedCategory(id); - }} - /> - ) : null; - - const cards = eprAndCustomPackages.map((item) => { - return mapToCard(getAbsolutePath, getHref, item); - }); - - return ( - - ); -}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx new file mode 100644 index 0000000000000..404e8820f90b7 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useMemo } from 'react'; +import { useLocation, useHistory, useParams } from 'react-router-dom'; +import semverLt from 'semver/functions/lt'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiCallOut, EuiLink } from '@elastic/eui'; + +import { installationStatuses } from '../../../../../../../common/constants'; +import { pagePathGetters } from '../../../../constants'; +import { useGetPackages, useBreadcrumbs, useLink, useStartServices } from '../../../../hooks'; +import { PackageListGrid } from '../../components/package_list_grid'; + +import type { CategoryFacet } from './category_facets'; +import { CategoryFacets } from './category_facets'; + +import type { CategoryParams } from '.'; +import { getParams, categoryExists, mapToCard } from '.'; + +const AnnouncementLink = () => { + const { docLinks } = useStartServices(); + + return ( + + {i18n.translate('xpack.fleet.epmList.availableCalloutBlogText', { + defaultMessage: 'announcement blog post', + })} + + ); +}; + +const Callout = () => ( + +

+ , + }} + /> +

+
+); + +const title = i18n.translate('xpack.fleet.epmList.installedTitle', { + defaultMessage: 'Installed integrations', +}); + +// TODO: clintandrewhall - this component is hard to test due to the hooks, particularly those that use `http` +// or `location` to load data. Ideally, we'll split this into "connected" and "pure" components. +export const InstalledPackages: React.FC = memo(() => { + useBreadcrumbs('integrations_installed'); + + const { data: allPackages, isLoading } = useGetPackages({ + experimental: true, + }); + + const { getHref, getAbsolutePath } = useLink(); + + const { selectedCategory, searchParam } = getParams( + useParams(), + useLocation().search + ); + + const history = useHistory(); + + function setSelectedCategory(categoryId: string) { + const url = pagePathGetters.integrations_installed({ + category: categoryId, + searchTerm: searchParam, + })[1]; + + history.push(url); + } + + function setSearchTerm(search: string) { + // Use .replace so the browser's back button is not tied to single keystroke + history.replace( + pagePathGetters.integrations_installed({ + category: selectedCategory, + searchTerm: search, + })[1] + ); + } + + const allInstalledPackages = useMemo( + () => + (allPackages?.response || []).filter((pkg) => pkg.status === installationStatuses.Installed), + [allPackages?.response] + ); + + const updatablePackages = useMemo( + () => + allInstalledPackages.filter( + (item) => + 'savedObject' in item && semverLt(item.savedObject.attributes.version, item.version) + ), + [allInstalledPackages] + ); + + const categories: CategoryFacet[] = useMemo( + () => [ + { + id: '', + count: allInstalledPackages.length, + }, + { + id: 'updates_available', + count: updatablePackages.length, + }, + ], + [allInstalledPackages.length, updatablePackages.length] + ); + + if (!categoryExists(selectedCategory, categories)) { + history.replace( + pagePathGetters.integrations_installed({ category: '', searchTerm: searchParam })[1] + ); + + return null; + } + + const controls = ( + setSelectedCategory(id)} + /> + ); + + const cards = ( + selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages + ).map((item) => mapToCard(getAbsolutePath, getHref, item)); + + const callout = selectedCategory === 'updates_available' ? null : ; + + return ( + + ); +}); From 8ea719ca8a25d5bd421d5fadc92698cb6545f98b Mon Sep 17 00:00:00 2001 From: Milton Hultgren Date: Tue, 12 Oct 2021 08:46:48 +0200 Subject: [PATCH 34/73] [Logs UI][Metrics UI] Replace usage of deprecated IndexPattern types (#114448) * [Logs UI][Metrics UI] Replace usage of deprecated IndexPattern types (#107887) --- .../common/dependency_mocks/index_patterns.ts | 18 ++++++---------- .../resolved_log_source_configuration.ts | 12 +++++------ .../components/expression_chart.test.tsx | 4 ++-- .../components/expression_chart.tsx | 4 ++-- .../hooks/use_metrics_explorer_chart_data.ts | 4 ++-- .../logs/log_filter/log_filter_state.ts | 5 +++-- .../containers/logs/log_source/log_source.ts | 4 ++-- .../containers/with_kuery_autocompletion.tsx | 6 ++++-- .../containers/with_source/with_source.tsx | 4 ++-- .../hooks/use_kibana_index_patterns.mock.tsx | 21 +++++++------------ .../indices_configuration_panel.stories.tsx | 3 +++ .../pages/logs/settings/validation_errors.ts | 13 ++++++------ .../infra/public/pages/metrics/index.tsx | 4 ++-- .../components/toolbars/toolbar.tsx | 4 ++-- .../metrics_explorer/components/kuery_bar.tsx | 9 +++----- .../metrics_explorer/components/toolbar.tsx | 5 +++-- .../hooks/use_metric_explorer_state.ts | 4 ++-- .../hooks/use_metrics_explorer_data.test.tsx | 4 ++-- .../hooks/use_metrics_explorer_data.ts | 4 ++-- .../pages/metrics/metrics_explorer/index.tsx | 4 ++-- x-pack/plugins/infra/public/utils/kuery.ts | 5 +++-- .../utils/logs_overview_fetches.test.ts | 1 + .../log_entries_search_strategy.test.ts | 1 + .../log_entry_search_strategy.test.ts | 1 + 24 files changed, 69 insertions(+), 75 deletions(-) diff --git a/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts b/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts index 14215c1539473..03d3ec757bf55 100644 --- a/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts +++ b/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts @@ -7,17 +7,11 @@ import { from, of } from 'rxjs'; import { delay } from 'rxjs/operators'; -import { - fieldList, - FieldSpec, - IIndexPattern, - IndexPattern, - IndexPatternsContract, - RuntimeField, -} from 'src/plugins/data/common'; +import { DataView, DataViewsContract } from '../../../../../src/plugins/data_views/common'; +import { fieldList, FieldSpec, RuntimeField } from '../../../../../src/plugins/data/common'; type IndexPatternMock = Pick< - IndexPattern, + DataView, | 'fields' | 'getComputedFields' | 'getFieldByName' @@ -27,7 +21,7 @@ type IndexPatternMock = Pick< | 'title' | 'type' >; -type IndexPatternMockSpec = Pick & { +type IndexPatternMockSpec = Pick & { fields: FieldSpec[]; }; @@ -71,8 +65,8 @@ export const createIndexPatternsMock = ( asyncDelay: number, indexPatterns: IndexPatternMock[] ): { - getIdsWithTitle: IndexPatternsContract['getIdsWithTitle']; - get: (...args: Parameters) => Promise; + getIdsWithTitle: DataViewsContract['getIdsWithTitle']; + get: (...args: Parameters) => Promise; } => { return { async getIdsWithTitle(_refresh?: boolean) { diff --git a/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts b/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts index 9c41a216c7f92..567acf1fc4134 100644 --- a/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts +++ b/x-pack/plugins/infra/common/log_sources/resolved_log_source_configuration.ts @@ -6,7 +6,7 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { IndexPattern, IndexPatternsContract } from '../../../../../src/plugins/data/common'; +import { DataView, DataViewsContract } from '../../../../../src/plugins/data_views/common'; import { ObjectEntries } from '../utility_types'; import { ResolveLogSourceConfigurationError } from './errors'; import { @@ -21,14 +21,14 @@ export interface ResolvedLogSourceConfiguration { timestampField: string; tiebreakerField: string; messageField: string[]; - fields: IndexPattern['fields']; + fields: DataView['fields']; runtimeMappings: estypes.MappingRuntimeFields; columns: LogSourceColumnConfiguration[]; } export const resolveLogSourceConfiguration = async ( sourceConfiguration: LogSourceConfigurationProperties, - indexPatternsService: IndexPatternsContract + indexPatternsService: DataViewsContract ): Promise => { if (sourceConfiguration.logIndices.type === 'index_name') { return await resolveLegacyReference(sourceConfiguration, indexPatternsService); @@ -39,7 +39,7 @@ export const resolveLogSourceConfiguration = async ( const resolveLegacyReference = async ( sourceConfiguration: LogSourceConfigurationProperties, - indexPatternsService: IndexPatternsContract + indexPatternsService: DataViewsContract ): Promise => { if (sourceConfiguration.logIndices.type !== 'index_name') { throw new Error('This function can only resolve legacy references'); @@ -74,7 +74,7 @@ const resolveLegacyReference = async ( const resolveKibanaIndexPatternReference = async ( sourceConfiguration: LogSourceConfigurationProperties, - indexPatternsService: IndexPatternsContract + indexPatternsService: DataViewsContract ): Promise => { if (sourceConfiguration.logIndices.type !== 'index_pattern') { throw new Error('This function can only resolve Kibana Index Pattern references'); @@ -103,7 +103,7 @@ const resolveKibanaIndexPatternReference = async ( }; // this might take other sources of runtime fields into account in the future -const resolveRuntimeMappings = (indexPattern: IndexPattern): estypes.MappingRuntimeFields => { +const resolveRuntimeMappings = (indexPattern: DataView): estypes.MappingRuntimeFields => { const { runtimeFields } = indexPattern.getComputedFields(); const runtimeMappingsFromIndexPattern = ( diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx index caf8e32814fe5..5aafd9b613d99 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx @@ -9,7 +9,7 @@ import { mountWithIntl, nextTick } from '@kbn/test/jest'; // We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` import { coreMock as mockCoreMock } from 'src/core/public/mocks'; import { MetricExpression } from '../types'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfiguration } from '../../../../common/metrics_sources'; import React from 'react'; import { ExpressionChart } from './expression_chart'; @@ -40,7 +40,7 @@ jest.mock('../hooks/use_metrics_explorer_chart_data', () => ({ describe('ExpressionChart', () => { async function setup(expression: MetricExpression, filterQuery?: string, groupBy?: string) { - const derivedIndexPattern: IIndexPattern = { + const derivedIndexPattern: DataViewBase = { title: 'metricbeat-*', fields: [], }; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx index e5558b961ab20..b176e3907228c 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx @@ -10,7 +10,7 @@ import { Axis, Chart, niceTimeFormatter, Position, Settings } from '@elastic/cha import { first, last } from 'lodash'; import { EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfiguration } from '../../../../common/metrics_sources'; import { Color } from '../../../../common/color_palette'; import { MetricsExplorerRow, MetricsExplorerAggregation } from '../../../../common/http_api'; @@ -34,7 +34,7 @@ import { ThresholdAnnotations } from '../../common/criterion_preview_chart/thres interface Props { expression: MetricExpression; - derivedIndexPattern: IIndexPattern; + derivedIndexPattern: DataViewBase; source: MetricsSourceConfiguration | null; filterQuery?: string; groupBy?: string | string[]; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.ts b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.ts index e3006993216ae..1ae1bacfed42e 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.ts +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { useMemo } from 'react'; import { MetricsSourceConfiguration } from '../../../../common/metrics_sources'; import { MetricExpression } from '../types'; @@ -14,7 +14,7 @@ import { useMetricsExplorerData } from '../../../pages/metrics/metrics_explorer/ export const useMetricsExplorerChartData = ( expression: MetricExpression, - derivedIndexPattern: IIndexPattern, + derivedIndexPattern: DataViewBase, source: MetricsSourceConfiguration | null, filterQuery?: string, groupBy?: string | string[] diff --git a/x-pack/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts b/x-pack/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts index d4cb7ca90541f..f4576158b9a25 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts @@ -8,7 +8,8 @@ import createContainer from 'constate'; import { useCallback, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; -import { esQuery, IIndexPattern, Query } from '../../../../../../../src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; +import { esQuery, Query } from '../../../../../../../src/plugins/data/public'; type ParsedQuery = ReturnType; @@ -33,7 +34,7 @@ const initialLogFilterState: ILogFilterState = { const validationDebounceTimeout = 1000; // milliseconds -export const useLogFilterState = ({ indexPattern }: { indexPattern: IIndexPattern }) => { +export const useLogFilterState = ({ indexPattern }: { indexPattern: DataViewBase }) => { const [logFilterState, setLogFilterState] = useState(initialLogFilterState); const parseQuery = useCallback( diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts index 198d0d2efe44c..8f744a1d6df6d 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts @@ -8,7 +8,7 @@ import createContainer from 'constate'; import { useCallback, useMemo, useState } from 'react'; import type { HttpHandler } from 'src/core/public'; -import { IndexPatternsContract } from '../../../../../../../src/plugins/data/common'; +import { DataViewsContract } from '../../../../../../../src/plugins/data_views/public'; import { LogIndexField, LogSourceConfigurationPropertiesPatch, @@ -42,7 +42,7 @@ export const useLogSource = ({ }: { sourceId: string; fetch: HttpHandler; - indexPatternsService: IndexPatternsContract; + indexPatternsService: DataViewsContract; }) => { const [sourceConfiguration, setSourceConfiguration] = useState< LogSourceConfiguration | undefined diff --git a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx index f50c629d521e5..0e5ef1ca78033 100644 --- a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -6,7 +6,8 @@ */ import React from 'react'; -import { QuerySuggestion, IIndexPattern, DataPublicPluginStart } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; +import { QuerySuggestion, DataPublicPluginStart } from 'src/plugins/data/public'; import { withKibana, KibanaReactContextValue, @@ -21,7 +22,7 @@ interface WithKueryAutocompletionLifecycleProps { loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; suggestions: QuerySuggestion[]; }>; - indexPattern: IIndexPattern; + indexPattern: DataViewBase; } interface WithKueryAutocompletionLifecycleState { @@ -82,6 +83,7 @@ class WithKueryAutocompletionComponent extends React.Component< query: expression, selectionStart: cursorPosition, selectionEnd: cursorPosition, + // @ts-expect-error (until data service updates to new types) indexPatterns: [indexPattern], boolFilter: [], })) || []; diff --git a/x-pack/plugins/infra/public/containers/with_source/with_source.tsx b/x-pack/plugins/infra/public/containers/with_source/with_source.tsx index f3ca57a40c4c7..aa7ab18271d99 100644 --- a/x-pack/plugins/infra/public/containers/with_source/with_source.tsx +++ b/x-pack/plugins/infra/public/containers/with_source/with_source.tsx @@ -7,7 +7,7 @@ import React, { useContext } from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfigurationProperties, PartialMetricsSourceConfigurationProperties, @@ -21,7 +21,7 @@ interface WithSourceProps { create: ( sourceProperties: PartialMetricsSourceConfigurationProperties ) => Promise | undefined; - createDerivedIndexPattern: (type: 'metrics') => IIndexPattern; + createDerivedIndexPattern: (type: 'metrics') => DataViewBase; exists?: boolean; hasFailed: boolean; isLoading: boolean; diff --git a/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx b/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx index 9d3a611cff88d..99cd094b50e1e 100644 --- a/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx +++ b/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx @@ -10,23 +10,16 @@ import { from, of } from 'rxjs'; import { delay } from 'rxjs/operators'; import { CoreStart } from '../../../../../src/core/public'; import { FieldSpec } from '../../../../../src/plugins/data/common'; -import { - IIndexPattern, - IndexPattern, - IndexPatternField, - IndexPatternsContract, -} from '../../../../../src/plugins/data/public'; +import { DataView, DataViewsContract } from '../../../../../src/plugins/data_views/public'; +import { DataViewField } from '../../../../../src/plugins/data_views/common'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; import { Pick2 } from '../../common/utility_types'; type MockIndexPattern = Pick< - IndexPattern, + DataView, 'id' | 'title' | 'type' | 'getTimeField' | 'isTimeBased' | 'getFieldByName' | 'getComputedFields' >; -export type MockIndexPatternSpec = Pick< - IIndexPattern, - 'id' | 'title' | 'type' | 'timeFieldName' -> & { +export type MockIndexPatternSpec = Pick & { fields: FieldSpec[]; }; @@ -59,8 +52,8 @@ export const createIndexPatternsMock = ( asyncDelay: number, indexPatterns: MockIndexPattern[] ): { - getIdsWithTitle: IndexPatternsContract['getIdsWithTitle']; - get: (...args: Parameters) => Promise; + getIdsWithTitle: DataViewsContract['getIdsWithTitle']; + get: (...args: Parameters) => Promise; } => { return { async getIdsWithTitle(_refresh?: boolean) { @@ -85,7 +78,7 @@ export const createIndexPatternMock = ({ fields, timeFieldName, }: MockIndexPatternSpec): MockIndexPattern => { - const indexPatternFields = fields.map((fieldSpec) => new IndexPatternField(fieldSpec)); + const indexPatternFields = fields.map((fieldSpec) => new DataViewField(fieldSpec)); return { id, diff --git a/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx b/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx index 8cc9f5b4357ef..546bb9aab0f33 100644 --- a/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx +++ b/x-pack/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx @@ -131,6 +131,7 @@ const defaultArgs: IndicesConfigurationPanelStoryArgs = { id: 'INDEX_PATTERN_A', title: 'pattern-a-*', timeFieldName: '@timestamp', + type: undefined, fields: [ { name: '@timestamp', @@ -149,6 +150,8 @@ const defaultArgs: IndicesConfigurationPanelStoryArgs = { { id: 'INDEX_PATTERN_B', title: 'pattern-b-*', + timeFieldName: '@timestamp', + type: undefined, fields: [], }, ], diff --git a/x-pack/plugins/infra/public/pages/logs/settings/validation_errors.ts b/x-pack/plugins/infra/public/pages/logs/settings/validation_errors.ts index 81b9297f8a70b..896fecc8d70dd 100644 --- a/x-pack/plugins/infra/public/pages/logs/settings/validation_errors.ts +++ b/x-pack/plugins/infra/public/pages/logs/settings/validation_errors.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { IndexPattern, KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; +import { DataView } from '../../../../../../../src/plugins/data_views/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; export interface GenericValidationError { type: 'generic'; @@ -67,7 +68,7 @@ export const validateStringNotEmpty = (fieldName: string, value: string): FormVa export const validateColumnListNotEmpty = (columns: unknown[]): FormValidationError[] => columns.length <= 0 ? [{ type: 'empty_column_list' }] : []; -export const validateIndexPattern = (indexPattern: IndexPattern): FormValidationError[] => { +export const validateIndexPattern = (indexPattern: DataView): FormValidationError[] => { return [ ...validateIndexPatternIsTimeBased(indexPattern), ...validateIndexPatternHasStringMessageField(indexPattern), @@ -75,9 +76,7 @@ export const validateIndexPattern = (indexPattern: IndexPattern): FormValidation ]; }; -export const validateIndexPatternIsTimeBased = ( - indexPattern: IndexPattern -): FormValidationError[] => +export const validateIndexPatternIsTimeBased = (indexPattern: DataView): FormValidationError[] => indexPattern.isTimeBased() ? [] : [ @@ -88,7 +87,7 @@ export const validateIndexPatternIsTimeBased = ( ]; export const validateIndexPatternHasStringMessageField = ( - indexPattern: IndexPattern + indexPattern: DataView ): FormValidationError[] => { const messageField = indexPattern.getFieldByName('message'); @@ -111,7 +110,7 @@ export const validateIndexPatternHasStringMessageField = ( } }; -export const validateIndexPatternIsntRollup = (indexPattern: IndexPattern): FormValidationError[] => +export const validateIndexPatternIsntRollup = (indexPattern: DataView): FormValidationError[] => indexPattern.type != null ? [ { diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index d4845a4dd9e44..ae375dc504e7a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -11,7 +11,7 @@ import React, { useContext } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiErrorBoundary, EuiHeaderLinks, EuiHeaderLink } from '@elastic/eui'; -import { IIndexPattern } from 'src/plugins/data/common'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfigurationProperties } from '../../../common/metrics_sources'; import { DocumentTitle } from '../../components/document_title'; import { HelpCenterContent } from '../../components/help_center_content'; @@ -141,7 +141,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { const PageContent = (props: { configuration: MetricsSourceConfigurationProperties; - createDerivedIndexPattern: (type: 'metrics') => IIndexPattern; + createDerivedIndexPattern: (type: 'metrics') => DataViewBase; }) => { const { createDerivedIndexPattern, configuration } = props; const { options } = useContext(MetricsExplorerOptionsContainer.Context); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx index 1c79807f139c3..14f4177798be8 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx @@ -7,6 +7,7 @@ import React, { FunctionComponent } from 'react'; import { EuiFlexItem } from '@elastic/eui'; +import { DataViewBase } from '@kbn/es-query'; import { useSourceContext } from '../../../../../containers/metrics_source'; import { SnapshotMetricInput, @@ -18,13 +19,12 @@ import { findToolbar } from '../../../../../../common/inventory_models/toolbars' import { ToolbarWrapper } from './toolbar_wrapper'; import { InfraGroupByOptions } from '../../../../../lib/lib'; -import { IIndexPattern } from '../../../../../../../../../src/plugins/data/public'; import { InventoryItemType } from '../../../../../../common/inventory_models/types'; import { WaffleOptionsState, WaffleSortOption } from '../../hooks/use_waffle_options'; import { useInventoryMeta } from '../../hooks/use_inventory_meta'; export interface ToolbarProps extends Omit { - createDerivedIndexPattern: (type: 'metrics') => IIndexPattern; + createDerivedIndexPattern: (type: 'metrics') => DataViewBase; changeMetric: (payload: SnapshotMetricInput) => void; changeGroupBy: (payload: SnapshotGroupBy) => void; changeCustomOptions: (payload: InfraGroupByOptions[]) => void; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index cf201c9a57f7c..2be5f14005b26 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -8,13 +8,10 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; +import { DataViewBase } from '@kbn/es-query'; import { WithKueryAutocompletion } from '../../../../containers/with_kuery_autocompletion'; import { AutocompleteField } from '../../../../components/autocomplete_field'; -import { - esKuery, - IIndexPattern, - QuerySuggestion, -} from '../../../../../../../../src/plugins/data/public'; +import { esKuery, QuerySuggestion } from '../../../../../../../../src/plugins/data/public'; type LoadSuggestionsFn = ( e: string, @@ -25,7 +22,7 @@ type LoadSuggestionsFn = ( export type CurryLoadSuggestionsType = (loadSuggestions: LoadSuggestionsFn) => LoadSuggestionsFn; interface Props { - derivedIndexPattern: IIndexPattern; + derivedIndexPattern: DataViewBase; onSubmit: (query: string) => void; onChange?: (query: string) => void; value?: string | null; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx index 64da554dee690..01b2d129a1f9e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx @@ -8,7 +8,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import { IIndexPattern, UI_SETTINGS } from '../../../../../../../../src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; +import { UI_SETTINGS } from '../../../../../../../../src/plugins/data/public'; import { MetricsExplorerMetric, MetricsExplorerAggregation, @@ -27,7 +28,7 @@ import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting'; import { mapKibanaQuickRangesToDatePickerRanges } from '../../../../utils/map_timepicker_quickranges_to_datepicker_ranges'; interface Props { - derivedIndexPattern: IIndexPattern; + derivedIndexPattern: DataViewBase; timeRange: MetricsExplorerTimeOptions; options: MetricsExplorerOptions; chartOptions: MetricsExplorerChartOptions; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts index a304c81ca1298..39eb7c928997b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts @@ -6,7 +6,7 @@ */ import { useState, useCallback, useContext } from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources'; import { MetricsExplorerMetric, @@ -29,7 +29,7 @@ export interface MetricExplorerViewState { export const useMetricsExplorerState = ( source: MetricsSourceConfigurationProperties, - derivedIndexPattern: IIndexPattern, + derivedIndexPattern: DataViewBase, shouldLoadImmediately = true ) => { const [refreshSignal, setRefreshSignal] = useState(0); diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx index 9a5e5fcf39ce4..0f903e4c4553a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx @@ -20,7 +20,7 @@ import { createSeries, } from '../../../../utils/fixtures/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions } from './use_metrics_explorer_options'; -import { IIndexPattern } from '../../../../../../../../src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { HttpHandler } from 'kibana/public'; import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources'; @@ -39,7 +39,7 @@ const renderUseMetricsExplorerDataHook = () => { (props: { options: MetricsExplorerOptions; source: MetricsSourceConfigurationProperties | undefined; - derivedIndexPattern: IIndexPattern; + derivedIndexPattern: DataViewBase; timeRange: MetricsExplorerTimeOptions; afterKey: string | null | Record; signal: any; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index 95f98e172541a..6b7e98912fd49 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -8,7 +8,7 @@ import DateMath from '@elastic/datemath'; import { isEqual } from 'lodash'; import { useEffect, useState } from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfigurationProperties } from '../../../../../common/metrics_sources'; import { MetricsExplorerResponse, @@ -27,7 +27,7 @@ function isSameOptions(current: MetricsExplorerOptions, next: MetricsExplorerOpt export function useMetricsExplorerData( options: MetricsExplorerOptions, source: MetricsSourceConfigurationProperties | undefined, - derivedIndexPattern: IIndexPattern, + derivedIndexPattern: DataViewBase, timerange: MetricsExplorerTimeOptions, afterKey: string | null | Record, signal: any, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx index f2345b0b8e020..dabf5db9afe92 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx @@ -8,7 +8,7 @@ import { EuiErrorBoundary } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useContext } from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; import { MetricsSourceConfigurationProperties } from '../../../../common/metrics_sources'; import { useTrackPageview } from '../../../../../observability/public'; import { useMetricsBreadcrumbs } from '../../../hooks/use_metrics_breadcrumbs'; @@ -25,7 +25,7 @@ import { SavedViewsToolbarControls } from '../../../components/saved_views/toolb interface MetricsExplorerPageProps { source: MetricsSourceConfigurationProperties; - derivedIndexPattern: IIndexPattern; + derivedIndexPattern: DataViewBase; } export const MetricsExplorerPage = ({ source, derivedIndexPattern }: MetricsExplorerPageProps) => { diff --git a/x-pack/plugins/infra/public/utils/kuery.ts b/x-pack/plugins/infra/public/utils/kuery.ts index 19706d7664c22..c7528b237cce5 100644 --- a/x-pack/plugins/infra/public/utils/kuery.ts +++ b/x-pack/plugins/infra/public/utils/kuery.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { esKuery, IIndexPattern } from '../../../../../src/plugins/data/public'; +import { DataViewBase } from '@kbn/es-query'; +import { esKuery } from '../../../../../src/plugins/data/public'; export const convertKueryToElasticSearchQuery = ( kueryExpression: string, - indexPattern: IIndexPattern + indexPattern: DataViewBase ) => { try { return kueryExpression diff --git a/x-pack/plugins/infra/public/utils/logs_overview_fetches.test.ts b/x-pack/plugins/infra/public/utils/logs_overview_fetches.test.ts index 6dfb400567717..4fcb83fd02754 100644 --- a/x-pack/plugins/infra/public/utils/logs_overview_fetches.test.ts +++ b/x-pack/plugins/infra/public/utils/logs_overview_fetches.test.ts @@ -48,6 +48,7 @@ function setup() { id: 'test-index-pattern', title: 'log-indices-*', timeFieldName: '@timestamp', + type: undefined, fields: [ { name: 'event.dataset', diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts index 876aad4ef8d02..85a1b95cf70aa 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts @@ -342,6 +342,7 @@ const createDataPluginMock = (esSearchStrategyMock: ISearchStrategy): any => ({ id: 'test-index-pattern', title: 'log-indices-*', timeFieldName: '@timestamp', + type: undefined, fields: [ { name: 'event.dataset', diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts index 88c9d956dbe0a..ec3d4aa52a6b5 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts @@ -297,6 +297,7 @@ const createDataPluginMock = (esSearchStrategyMock: ISearchStrategy): any => ({ id: 'test-index-pattern', title: 'log-indices-*', timeFieldName: '@timestamp', + type: undefined, fields: [ { name: 'event.dataset', From b5771c81ba190031a1dca1876b57faf46d4c99a1 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Tue, 12 Oct 2021 10:55:53 +0200 Subject: [PATCH 35/73] [Stack Monitoring] functional tests - properly set test-subj attribute (#114491) * properly set test-subj attribute * fix prettier error * Fixing ESLinting issue Co-authored-by: Chris Cowan Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/pages/kibana/instance.tsx | 9 ++------- .../public/application/pages/kibana/instances.tsx | 7 +------ .../public/application/pages/kibana/kibana_template.tsx | 2 ++ .../public/application/pages/kibana/overview.tsx | 7 +------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx b/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx index 444794d118b0f..2d2fe99758ff7 100644 --- a/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/kibana/instance.tsx @@ -164,13 +164,8 @@ export const KibanaInstancePage: React.FC = ({ clusters }) => { }, [ccs, clusterUuid, instance, services.data?.query.timefilter.timefilter, services.http]); return ( - -
+ +
diff --git a/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx b/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx index ae0237ea40472..076e9413216fb 100644 --- a/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/kibana/instances.tsx @@ -87,12 +87,7 @@ export const KibanaInstancesPage: React.FC = ({ clusters }) => { ]); return ( - +
= ({ ...props }) => { defaultMessage: 'Overview', }), route: '/kibana', + testSubj: 'kibanaOverviewPage', }, { id: 'instances', @@ -23,6 +24,7 @@ export const KibanaTemplate: React.FC = ({ ...props }) => { defaultMessage: 'Instances', }), route: '/kibana/instances', + testSubj: 'kibanaInstancesPage', }, ]; diff --git a/x-pack/plugins/monitoring/public/application/pages/kibana/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/kibana/overview.tsx index a47da048e1936..4c480bf1fbb33 100644 --- a/x-pack/plugins/monitoring/public/application/pages/kibana/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/kibana/overview.tsx @@ -107,12 +107,7 @@ export const KibanaOverviewPage: React.FC = ({ clusters }) => { }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]); return ( - + ); From a0d36e7a699bc212a5de0b1ad305f33d05b3f73a Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 12 Oct 2021 11:24:55 +0200 Subject: [PATCH 36/73] [Discover/Reporting] Fix potential time drift with relative time when requesting a report (#114274) * updated Discover getSharingData to accept flag for absolute time * update snapshots * simplify fallback title * more appropriate title? * remove old translations * implement PR feedback Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/top_nav/get_top_nav_links.ts | 4 +-- .../apps/main/utils/get_sharing_data.test.ts | 36 +++---------------- .../apps/main/utils/get_sharing_data.ts | 16 ++++++--- .../panel_actions/get_csv_panel_action.tsx | 4 +-- .../register_csv_reporting.tsx | 13 +++++-- .../reporting_panel_content.tsx | 4 +-- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 8 files changed, 32 insertions(+), 47 deletions(-) diff --git a/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts b/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts index ba4cd8c3cd524..81be662470306 100644 --- a/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts +++ b/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts @@ -7,7 +7,6 @@ */ import { i18n } from '@kbn/i18n'; -import moment from 'moment'; import type { IndexPattern, ISearchSource } from 'src/plugins/data/common'; import { showOpenSearchPanel } from './show_open_search_panel'; import { getSharingData, showPublicUrlSwitch } from '../../utils/get_sharing_data'; @@ -128,8 +127,7 @@ export const getTopNavLinks = ({ title: savedSearch.title || i18n.translate('discover.localMenu.fallbackReportTitle', { - defaultMessage: 'Discover search [{date}]', - values: { date: moment().toISOString(true) }, + defaultMessage: 'Untitled discover search', }), }, isDirty: !savedSearch.id || state.isAppStateDirty(), diff --git a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts index e7205c3f9bc69..9b518c23a5f89 100644 --- a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts @@ -41,14 +41,7 @@ describe('getSharingData', () => { expect(result).toMatchInlineSnapshot(` Object { "columns": Array [], - "searchSource": Object { - "index": "the-index-pattern-id", - "sort": Array [ - Object { - "_score": "desc", - }, - ], - }, + "getSearchSource": [Function], } `); }); @@ -66,14 +59,7 @@ describe('getSharingData', () => { "column_a", "column_b", ], - "searchSource": Object { - "index": "the-index-pattern-id", - "sort": Array [ - Object { - "_score": "desc", - }, - ], - }, + "getSearchSource": [Function], } `); }); @@ -108,14 +94,7 @@ describe('getSharingData', () => { "cool-field-5", "cool-field-6", ], - "searchSource": Object { - "index": "the-index-pattern-id", - "sort": Array [ - Object { - "_doc": "desc", - }, - ], - }, + "getSearchSource": [Function], } `); }); @@ -158,14 +137,7 @@ describe('getSharingData', () => { "cool-field-5", "cool-field-6", ], - "searchSource": Object { - "index": "the-index-pattern-id", - "sort": Array [ - Object { - "_doc": false, - }, - ], - }, + "getSearchSource": [Function], } `); }); diff --git a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts index 420ff0fa11eeb..21292fabdd13f 100644 --- a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts @@ -9,7 +9,7 @@ import type { Capabilities } from 'kibana/public'; import type { IUiSettingsClient } from 'src/core/public'; import type { DataPublicPluginStart } from 'src/plugins/data/public'; -import type { ISearchSource } from 'src/plugins/data/common'; +import type { ISearchSource, SearchSourceFields } from 'src/plugins/data/common'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common'; import type { SavedSearch, SortOrder } from '../../../../saved_searches/types'; import { getSortForSearchSource } from '../components/doc_table'; @@ -31,8 +31,8 @@ export async function getSharingData( 'sort', getSortForSearchSource(state.sort as SortOrder[], index, config.get(SORT_DEFAULT_ORDER_SETTING)) ); - // When sharing externally we preserve relative time values - searchSource.setField('filter', data.query.timefilter.timefilter.createRelativeFilter(index)); + + searchSource.removeField('filter'); searchSource.removeField('highlight'); searchSource.removeField('highlightAll'); searchSource.removeField('aggs'); @@ -54,7 +54,15 @@ export async function getSharingData( } return { - searchSource: searchSource.getSerializedFields(true), + getSearchSource: (absoluteTime?: boolean): SearchSourceFields => { + const filter = absoluteTime + ? data.query.timefilter.timefilter.createFilter(index) + : data.query.timefilter.timefilter.createRelativeFilter(index); + + searchSource.setField('filter', filter); + + return searchSource.getSerializedFields(true); + }, columns, }; } diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx index ef32e64741765..115d7599c6bc8 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx @@ -117,10 +117,10 @@ export class ReportingCsvPanelAction implements ActionDefinition } const savedSearch = embeddable.getSavedSearch(); - const { columns, searchSource } = await this.getSearchSource(savedSearch, embeddable); + const { columns, getSearchSource } = await this.getSearchSource(savedSearch, embeddable); const immediateJobParams = this.apiClient.getDecoratedJobParams({ - searchSource, + searchSource: getSearchSource(true), columns, title: savedSearch.title, objectType: 'downloadCsv', // FIXME: added for typescript, but immediate download job does not need objectType diff --git a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx index 040a1646ec1ba..8859d01e4fe9a 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx @@ -48,14 +48,23 @@ export const ReportingCsvShareProvider = ({ return []; } + const getSearchSource = sharingData.getSearchSource as ( + absoluteTime?: boolean + ) => SearchSourceFields; + const jobParams = { title: sharingData.title as string, objectType, - searchSource: sharingData.searchSource as SearchSourceFields, columns: sharingData.columns as string[] | undefined, }; - const getJobParams = () => jobParams; + const getJobParams = (forShareUrl?: boolean) => { + const absoluteTime = !forShareUrl; + return { + ...jobParams, + searchSource: getSearchSource(absoluteTime), + }; + }; const shareActions = []; diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content.tsx index 59afa91aaa9c3..6ed6f2d0c5f49 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content.tsx @@ -40,7 +40,7 @@ export interface ReportingPanelProps { requiresSavedState: boolean; // Whether the report to be generated requires saved state that is not captured in the URL submitted to the report generator. layoutId?: string; objectId?: string; - getJobParams: () => Omit; + getJobParams: (forShareUrl?: boolean) => Omit; options?: ReactElement | null; isDirty?: boolean; onClose?: () => void; @@ -75,7 +75,7 @@ class ReportingPanelContentUi extends Component { private getAbsoluteReportGenerationUrl = (props: Props) => { const relativePath = this.props.apiClient.getReportingJobPath( props.reportType, - this.props.apiClient.getDecoratedJobParams(this.props.getJobParams()) + this.props.apiClient.getDecoratedJobParams(this.props.getJobParams(true)) ); return url.resolve(window.location.href, relativePath); // FIXME: '(from: string, to: string): string' is deprecated }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index fbd9352fb427f..642668bcecf34 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2522,7 +2522,6 @@ "discover.loadingDocuments": "ドキュメントを読み込み中", "discover.loadingJSON": "JSONを読み込んでいます", "discover.loadingResults": "結果を読み込み中", - "discover.localMenu.fallbackReportTitle": "Discover検索[{date}]", "discover.localMenu.inspectTitle": "検査", "discover.localMenu.localMenu.newSearchTitle": "新規", "discover.localMenu.localMenu.optionsTitle": "オプション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9408bb85db879..4d86994c0fb84 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2548,7 +2548,6 @@ "discover.loadingDocuments": "正在加载文档", "discover.loadingJSON": "正在加载 JSON", "discover.loadingResults": "正在加载结果", - "discover.localMenu.fallbackReportTitle": "Discover 搜索 [{date}]", "discover.localMenu.inspectTitle": "检查", "discover.localMenu.localMenu.newSearchTitle": "新建", "discover.localMenu.localMenu.optionsTitle": "选项", From 14cde79e8327430b0a16a7f266f3d6bbfc971226 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 12 Oct 2021 12:23:46 +0200 Subject: [PATCH 37/73] [ML] APM Correlations: Show trace samples even when overall histogram chart fails to load. (#114247) In the trace samples tab, the trace samples will not be shown if the overall histogram chart fails to load. This PR removes that limitation and will show the trace samples even when the chart fails to load. --- .../distribution/index.tsx | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index ca162be92cdae..97f38a8123a4e 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -222,18 +222,14 @@ export function TransactionDistribution({ status={status} /> - {hasData && ( - <> - - - - - )} + + +
); } From 7d6aba5188de1ac2e2608982399c68ee56cd8de1 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 12 Oct 2021 12:28:21 +0200 Subject: [PATCH 38/73] [Uptime] Make uptime settings saved object exportable (#114235) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/uptime/server/lib/saved_objects.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x-pack/plugins/uptime/server/lib/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects.ts index 3cd246175d0be..3e9888df55aa0 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../common/constants'; import { DynamicSettings } from '../../common/runtime_types'; import { SavedObjectsType, SavedObjectsErrorHelpers } from '../../../../../src/core/server'; @@ -43,6 +44,14 @@ export const umDynamicSettings: SavedObjectsType = { */ }, }, + management: { + importableAndExportable: true, + icon: 'uptimeApp', + getTitle: () => + i18n.translate('xpack.uptime.uptimeSettings.index', { + defaultMessage: 'Uptime Settings - Index', + }), + }, }; export const savedObjectsAdapter: UMSavedObjectsAdapter = { From 7617dc118514ffcfa0db583f00c755cd2dca3e91 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 12 Oct 2021 12:47:43 +0100 Subject: [PATCH 39/73] skip flaky suite (#114396) --- .../public/components/common/uptime_date_picker.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx b/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx index 997831442faa2..cd122eb5d5fc5 100644 --- a/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx @@ -12,7 +12,8 @@ import { createMemoryHistory } from 'history'; import { render } from '../../lib/helper/rtl_helpers'; import { fireEvent } from '@testing-library/dom'; -describe('UptimeDatePicker component', () => { +// FLAKY: https://github.com/elastic/kibana/issues/114396 +describe.skip('UptimeDatePicker component', () => { it('renders properly with mock data', async () => { const { findByText } = render(); expect(await findByText('Last 15 minutes')).toBeInTheDocument(); From a11c3374c44144624916f360636d1af23df8faa8 Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Tue, 12 Oct 2021 07:53:26 -0400 Subject: [PATCH 40/73] Handle deletes (#114545) --- .../curation_suggestion_logic.test.ts | 72 +++++++++++++++++++ .../curation_suggestion_logic.ts | 47 +++++++++--- 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts index 2ace55133d6fd..7a91171cc2cc7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts @@ -357,6 +357,42 @@ describe('CurationSuggestionLogic', () => { ); }); + describe('when a suggestion is a "delete" suggestion', () => { + const deleteSuggestion = { + ...suggestion, + operation: 'delete', + promoted: [], + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }; + + it('will show a confirm message before applying, and redirect a user back to the curations page, rather than the curation details page', async () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(true); + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [{ ...suggestion, status: 'accepted', curation_id: undefined }], + }) + ); + mountLogic({ + suggestion: deleteSuggestion, + }); + CurationSuggestionLogic.actions.acceptSuggestion(); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + it('will do nothing if the user does not confirm', async () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(false); + mountLogic({ + suggestion: deleteSuggestion, + }); + CurationSuggestionLogic.actions.acceptSuggestion(); + await nextTick(); + expect(http.put).not.toHaveBeenCalled(); + expect(navigateToUrl).not.toHaveBeenCalled(); + }); + }); + itHandlesErrors(http.put, () => { CurationSuggestionLogic.actions.acceptSuggestion(); }); @@ -404,6 +440,42 @@ describe('CurationSuggestionLogic', () => { ); }); + describe('when a suggestion is a "delete" suggestion', () => { + const deleteSuggestion = { + ...suggestion, + operation: 'delete', + promoted: [], + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }; + + it('will show a confirm message before applying, and redirect a user back to the curations page, rather than the curation details page', async () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(true); + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [{ ...suggestion, status: 'accepted', curation_id: undefined }], + }) + ); + mountLogic({ + suggestion: deleteSuggestion, + }); + CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + it('will do nothing if the user does not confirm', async () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(false); + mountLogic({ + suggestion: deleteSuggestion, + }); + CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); + await nextTick(); + expect(http.put).not.toHaveBeenCalled(); + expect(navigateToUrl).not.toHaveBeenCalled(); + }); + }); + itHandlesErrors(http.put, () => { CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts index 6749b510edeba..4ca1b0adb7814 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts @@ -141,6 +141,11 @@ export const CurationSuggestionLogic = kea< const { engineName } = EngineLogic.values; const { suggestion } = values; + if (suggestion!.operation === 'delete') { + const confirmed = await confirmDialog('Are you sure you want to delete this curation?'); + if (!confirmed) return; + } + try { const updatedSuggestion = await updateSuggestion( http, @@ -155,11 +160,16 @@ export const CurationSuggestionLogic = kea< { defaultMessage: 'Suggestion was succefully applied.' } ) ); - KibanaLogic.values.navigateToUrl( - generateEnginePath(ENGINE_CURATION_PATH, { - curationId: updatedSuggestion.curation_id, - }) - ); + if (suggestion!.operation === 'delete') { + // Because if a curation is deleted, there will be no curation detail page to navigate to afterwards. + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + } else { + KibanaLogic.values.navigateToUrl( + generateEnginePath(ENGINE_CURATION_PATH, { + curationId: updatedSuggestion.curation_id, + }) + ); + } } catch (e) { flashAPIErrors(e); } @@ -169,6 +179,11 @@ export const CurationSuggestionLogic = kea< const { engineName } = EngineLogic.values; const { suggestion } = values; + if (suggestion!.operation === 'delete') { + const confirmed = await confirmDialog('Are you sure you want to delete this curation?'); + if (!confirmed) return; + } + try { const updatedSuggestion = await updateSuggestion( http, @@ -187,11 +202,16 @@ export const CurationSuggestionLogic = kea< } ) ); - KibanaLogic.values.navigateToUrl( - generateEnginePath(ENGINE_CURATION_PATH, { - curationId: updatedSuggestion.curation_id, - }) - ); + if (suggestion!.operation === 'delete') { + // Because if a curation is deleted, there will be no curation detail page to navigate to afterwards. + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + } else { + KibanaLogic.values.navigateToUrl( + generateEnginePath(ENGINE_CURATION_PATH, { + curationId: updatedSuggestion.curation_id, + }) + ); + } } catch (e) { flashAPIErrors(e); } @@ -325,3 +345,10 @@ const getCuration = async (http: HttpSetup, engineName: string, curationId: stri query: { skip_record_analytics: 'true' }, }); }; + +const confirmDialog = (msg: string) => { + return new Promise(function (resolve) { + const confirmed = window.confirm(msg); + return resolve(confirmed); + }); +}; From eb5e46a094bfea7b9e2dc56d849762c3a4a0bcd0 Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Tue, 12 Oct 2021 07:53:48 -0400 Subject: [PATCH 41/73] Check platinum license (#114549) --- .../curations/views/curations_overview.test.tsx | 16 ++++++++++++++++ .../curations/views/curations_overview.tsx | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx index 32ea59c8192ba..ff6ee66d8cb10 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx @@ -15,6 +15,8 @@ import { shallow } from 'enzyme'; import { CurationsTable, EmptyState } from '../components'; +import { SuggestionsTable } from '../components/suggestions_table'; + import { CurationsOverview } from './curations_overview'; describe('CurationsOverview', () => { @@ -44,4 +46,18 @@ describe('CurationsOverview', () => { expect(wrapper.find(CurationsTable)).toHaveLength(1); }); + + it('renders a suggestions table when the user has a platinum license', () => { + setMockValues({ curations: [], hasPlatinumLicense: true }); + const wrapper = shallow(); + + expect(wrapper.find(SuggestionsTable).exists()).toBe(true); + }); + + it('doesn\t render a suggestions table when the user has no platinum license', () => { + setMockValues({ curations: [], hasPlatinumLicense: false }); + const wrapper = shallow(); + + expect(wrapper.find(SuggestionsTable).exists()).toBe(false); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx index 7d3db5dedb262..079f0046cb9bf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx @@ -11,15 +11,16 @@ import { useValues } from 'kea'; import { EuiSpacer } from '@elastic/eui'; +import { LicensingLogic } from '../../../../shared/licensing'; import { CurationsTable, EmptyState } from '../components'; import { SuggestionsTable } from '../components/suggestions_table'; import { CurationsLogic } from '../curations_logic'; export const CurationsOverview: React.FC = () => { const { curations } = useValues(CurationsLogic); + const { hasPlatinumLicense } = useValues(LicensingLogic); - // TODO - const shouldShowSuggestions = true; + const shouldShowSuggestions = hasPlatinumLicense; return ( <> From adb49b7d37a3a368f938307c7df09729fdba43c7 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 12 Oct 2021 14:06:31 +0200 Subject: [PATCH 42/73] refactor (#114603) --- .../cypress/integration/timelines/pagination.spec.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/pagination.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/pagination.spec.ts index b569ea7cc082f..ce7b589f53c5a 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/pagination.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/pagination.spec.ts @@ -24,7 +24,7 @@ import { HOSTS_URL } from '../../urls/navigation'; const defaultPageSize = 25; describe('Pagination', () => { - beforeEach(() => { + before(() => { cleanKibana(); loginAndWaitForPage(HOSTS_URL); openTimelineUsingToggle(); @@ -41,20 +41,13 @@ describe('Pagination', () => { it('should be able to change items count per page with the dropdown', () => { const itemsPerPage = 100; - cy.intercept('POST', '/internal/bsearch').as('refetch'); - cy.get(TIMELINE_EVENTS_COUNT_PER_PAGE_BTN).first().click(); cy.get(TIMELINE_EVENTS_COUNT_PER_PAGE_OPTION(itemsPerPage)).click(); - cy.wait('@refetch').its('response.statusCode').should('eq', 200); cy.get(TIMELINE_EVENTS_COUNT_PER_PAGE).should('contain.text', itemsPerPage); }); it('should be able to go to next / previous page', () => { - cy.intercept('POST', '/internal/bsearch').as('refetch'); cy.get(`${TIMELINE_FLYOUT} ${TIMELINE_EVENTS_COUNT_NEXT_PAGE}`).first().click(); - cy.wait('@refetch').its('response.statusCode').should('eq', 200); - cy.get(`${TIMELINE_FLYOUT} ${TIMELINE_EVENTS_COUNT_PREV_PAGE}`).first().click(); - cy.wait('@refetch').its('response.statusCode').should('eq', 200); }); }); From 9e65b12c4b6bd8b048994e92a7d4a970862e2372 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 12 Oct 2021 06:29:36 -0600 Subject: [PATCH 43/73] [Maps] Fix apis Maps endpoints getTile should return vector tile containing document (#114509) * [Maps] Fix apis Maps endpoints getTile should return vector tile containing document * use find instead of if statement * eslint * can not use layer.feature.find is layer.feature is not an array * unskip other test where fix has been merged Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../api_integration/apis/maps/get_tile.js | 27 ++++++++++++++----- .../maps/documents_source/docvalue_fields.js | 3 +-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/x-pack/test/api_integration/apis/maps/get_tile.js b/x-pack/test/api_integration/apis/maps/get_tile.js index b153cc1ff030c..a1d4f10ca7be8 100644 --- a/x-pack/test/api_integration/apis/maps/get_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_tile.js @@ -10,11 +10,19 @@ import Protobuf from 'pbf'; import expect from '@kbn/expect'; import { MVT_SOURCE_LAYER_NAME } from '../../../../plugins/maps/common/constants'; +function findFeature(layer, callbackFn) { + for (let i = 0; i < layer.length; i++) { + const feature = layer.feature(i); + if (callbackFn(feature)) { + return feature; + } + } +} + export default function ({ getService }) { const supertest = getService('supertest'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/114471 - describe.skip('getTile', () => { + describe('getTile', () => { it('should return vector tile containing document', async () => { const resp = await supertest .get( @@ -32,8 +40,12 @@ export default function ({ getService }) { const layer = jsonTile.layers[MVT_SOURCE_LAYER_NAME]; expect(layer.length).to.be(3); // 2 docs + the metadata feature - // 1st doc - const feature = layer.feature(0); + // Verify ES document + + const feature = findFeature(layer, (feature) => { + return feature.properties._id === 'AU_x3_BsGFA8no6Qjjug'; + }); + expect(feature).not.to.be(undefined); expect(feature.type).to.be(1); expect(feature.extent).to.be(4096); expect(feature.id).to.be(undefined); @@ -46,8 +58,11 @@ export default function ({ getService }) { }); expect(feature.loadGeometry()).to.eql([[{ x: 44, y: 2382 }]]); - // Metadata feature - const metadataFeature = layer.feature(2); + // Verify metadata feature + const metadataFeature = findFeature(layer, (feature) => { + return feature.properties.__kbn_metadata_feature__; + }); + expect(metadataFeature).not.to.be(undefined); expect(metadataFeature.type).to.be(3); expect(metadataFeature.extent).to.be(4096); expect(metadataFeature.id).to.be(undefined); diff --git a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js index d1da193ac50a5..e24ba5b673169 100644 --- a/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js +++ b/x-pack/test/functional/apps/maps/documents_source/docvalue_fields.js @@ -11,8 +11,7 @@ export default function ({ getPageObjects, getService }) { const PageObjects = getPageObjects(['maps']); const security = getService('security'); - // FLAKY: https://github.com/elastic/kibana/issues/114418 - describe.skip('docvalue_fields', () => { + describe('docvalue_fields', () => { before(async () => { await security.testUser.setRoles(['global_maps_read', 'test_logstash_reader'], false); }); From e1133e11ac42ede0579312dda98fa58b3790259b Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 12 Oct 2021 14:35:14 +0200 Subject: [PATCH 44/73] [Discover] Improve context code (#114284) --- .../__mocks__/index_pattern_with_timefield.ts | 2 + .../apps/context/context_app.test.tsx | 1 - .../application/apps/context/context_app.tsx | 22 +- .../apps/context/context_app_content.tsx | 8 +- .../apps/context/context_app_route.tsx | 2 +- .../apps/context/services/_stubs.ts | 13 - .../apps/context/services/anchor.test.ts | 49 ++-- .../apps/context/services/anchor.ts | 51 ++-- .../services/context.predecessors.test.ts | 236 +++++++----------- .../services/context.successors.test.ts | 225 ++++++----------- .../apps/context/services/context.ts | 148 ++++++----- .../context/services/context_state.test.ts | 31 +-- .../apps/context/services/context_state.ts | 26 +- .../utils/use_context_app_fetch.test.ts | 33 ++- .../context/utils/use_context_app_fetch.tsx | 47 ++-- .../context/utils/use_context_app_state.ts | 12 +- 16 files changed, 342 insertions(+), 564 deletions(-) diff --git a/src/plugins/discover/public/__mocks__/index_pattern_with_timefield.ts b/src/plugins/discover/public/__mocks__/index_pattern_with_timefield.ts index f1f1d74f3af3a..0f64a6c67741d 100644 --- a/src/plugins/discover/public/__mocks__/index_pattern_with_timefield.ts +++ b/src/plugins/discover/public/__mocks__/index_pattern_with_timefield.ts @@ -72,6 +72,8 @@ const indexPattern = { getFieldByName: (name: string) => fields.getByName(name), timeFieldName: 'timestamp', getFormatterForField: () => ({ convert: () => 'formatted' }), + isTimeNanosBased: () => false, + popularizeField: () => {}, } as unknown as IndexPattern; indexPattern.flattenHit = indexPatterns.flattenHitWrapper(indexPattern, indexPattern.metaFields); diff --git a/src/plugins/discover/public/application/apps/context/context_app.test.tsx b/src/plugins/discover/public/application/apps/context/context_app.test.tsx index d54a4f8bed247..0e50f8f714a2c 100644 --- a/src/plugins/discover/public/application/apps/context/context_app.test.tsx +++ b/src/plugins/discover/public/application/apps/context/context_app.test.tsx @@ -26,7 +26,6 @@ const mockNavigationPlugin = { ui: { TopNavMenu: mockTopNavMenu } }; describe('ContextApp test', () => { const defaultProps = { indexPattern: indexPatternMock, - indexPatternId: 'the-index-pattern-id', anchorId: 'mocked_anchor_id', }; diff --git a/src/plugins/discover/public/application/apps/context/context_app.tsx b/src/plugins/discover/public/application/apps/context/context_app.tsx index 070391edae71c..9d39c93d250f2 100644 --- a/src/plugins/discover/public/application/apps/context/context_app.tsx +++ b/src/plugins/discover/public/application/apps/context/context_app.tsx @@ -12,7 +12,7 @@ import classNames from 'classnames'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText, EuiPageContent, EuiPage, EuiSpacer } from '@elastic/eui'; import { cloneDeep } from 'lodash'; -import { esFilters, SortDirection } from '../../../../../data/public'; +import { esFilters } from '../../../../../data/public'; import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '../../../../common'; import { ContextErrorMessage } from './components/context_error_message'; import { IndexPattern, IndexPatternField } from '../../../../../data/common'; @@ -31,21 +31,20 @@ const ContextAppContentMemoized = memo(ContextAppContent); export interface ContextAppProps { indexPattern: IndexPattern; - indexPatternId: string; anchorId: string; } -export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAppProps) => { +export const ContextApp = ({ indexPattern, anchorId }: ContextAppProps) => { const services = getServices(); - const { uiSettings: config, capabilities, indexPatterns, navigation, filterManager } = services; + const { uiSettings, capabilities, indexPatterns, navigation, filterManager } = services; - const isLegacy = useMemo(() => config.get(DOC_TABLE_LEGACY), [config]); - const useNewFieldsApi = useMemo(() => !config.get(SEARCH_FIELDS_FROM_SOURCE), [config]); + const isLegacy = useMemo(() => uiSettings.get(DOC_TABLE_LEGACY), [uiSettings]); + const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]); /** * Context app state */ - const { appState, setAppState } = useContextAppState({ indexPattern, services }); + const { appState, setAppState } = useContextAppState({ services }); const prevAppState = useRef(); /** @@ -54,7 +53,6 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp const { fetchedState, fetchContextRows, fetchAllRows, fetchSurroundingRows } = useContextAppFetch( { anchorId, - indexPatternId, indexPattern, appState, useNewFieldsApi, @@ -79,7 +77,6 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp prevAppState.current = cloneDeep(appState); }, [ appState, - indexPatternId, anchorId, fetchContextRows, fetchAllRows, @@ -89,7 +86,7 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp const { columns, onAddColumn, onRemoveColumn, onSetColumns } = useDataGridColumns({ capabilities, - config, + config: uiSettings, indexPattern, indexPatterns, state: appState, @@ -112,7 +109,7 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp field, values, operation, - indexPatternId + indexPattern.id! ); filterManager.addFilters(newFilters); if (indexPatterns) { @@ -120,7 +117,7 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp await popularizeField(indexPattern, fieldName, indexPatterns, capabilities); } }, - [filterManager, indexPatternId, indexPatterns, indexPattern, capabilities] + [filterManager, indexPatterns, indexPattern, capabilities] ); const TopNavMenu = navigation.ui.TopNavMenu; @@ -166,7 +163,6 @@ export const ContextApp = ({ indexPattern, indexPatternId, anchorId }: ContextAp onAddColumn={onAddColumn} onRemoveColumn={onRemoveColumn} onSetColumns={onSetColumns} - sort={appState.sort as [[string, SortDirection]]} predecessorCount={appState.predecessorCount} successorCount={appState.successorCount} setAppState={setAppState} diff --git a/src/plugins/discover/public/application/apps/context/context_app_content.tsx b/src/plugins/discover/public/application/apps/context/context_app_content.tsx index 19b6bfac2876c..2d4d3cab250f3 100644 --- a/src/plugins/discover/public/application/apps/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/apps/context/context_app_content.tsx @@ -22,6 +22,7 @@ import { DiscoverServices } from '../../../build_services'; import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from './utils/constants'; import { DocTableContext } from '../main/components/doc_table/doc_table_context'; import { EsHitRecordList } from '../../types'; +import { SortPairArr } from '../main/components/doc_table/lib/get_sort'; export interface ContextAppContentProps { columns: string[]; @@ -33,7 +34,6 @@ export interface ContextAppContentProps { predecessorCount: number; successorCount: number; rows: EsHitRecordList; - sort: [[string, SortDirection]]; predecessors: EsHitRecordList; successors: EsHitRecordList; anchorStatus: LoadingStatus; @@ -65,7 +65,6 @@ export function ContextAppContent({ predecessorCount, successorCount, rows, - sort, predecessors, successors, anchorStatus, @@ -111,6 +110,9 @@ export function ContextAppContent({ }, [setAppState] ); + const sort = useMemo(() => { + return [[indexPattern.timeFieldName!, SortDirection.desc]]; + }, [indexPattern]); return ( @@ -149,7 +151,7 @@ export function ContextAppContent({ expandedDoc={expandedDoc} isLoading={isAnchorLoading} sampleSize={0} - sort={sort} + sort={sort as SortPairArr[]} isSortEnabled={false} showTimeCol={showTimeCol} services={services} diff --git a/src/plugins/discover/public/application/apps/context/context_app_route.tsx b/src/plugins/discover/public/application/apps/context/context_app_route.tsx index 4bade3d03d993..d124fd6cfa395 100644 --- a/src/plugins/discover/public/application/apps/context/context_app_route.tsx +++ b/src/plugins/discover/public/application/apps/context/context_app_route.tsx @@ -49,5 +49,5 @@ export function ContextAppRoute(props: ContextAppProps) { return ; } - return ; + return ; } diff --git a/src/plugins/discover/public/application/apps/context/services/_stubs.ts b/src/plugins/discover/public/application/apps/context/services/_stubs.ts index 7e1473b876afc..e8d09e548c07a 100644 --- a/src/plugins/discover/public/application/apps/context/services/_stubs.ts +++ b/src/plugins/discover/public/application/apps/context/services/_stubs.ts @@ -9,7 +9,6 @@ import sinon from 'sinon'; import moment from 'moment'; -import { IndexPatternsContract } from '../../../../../../data/public'; import { EsHitRecordList } from '../../../types'; type SortHit = { @@ -18,18 +17,6 @@ type SortHit = { sort: [number, number]; }; -export function createIndexPatternsStub() { - return { - get: sinon.spy((indexPatternId) => - Promise.resolve({ - id: indexPatternId, - isTimeNanosBased: () => false, - popularizeField: () => {}, - }) - ), - } as unknown as IndexPatternsContract; -} - /** * A stubbed search source with a `fetch` method that returns all of `_stubHits`. */ diff --git a/src/plugins/discover/public/application/apps/context/services/anchor.test.ts b/src/plugins/discover/public/application/apps/context/services/anchor.test.ts index b4a76fa45ec2f..8886c8ab11f64 100644 --- a/src/plugins/discover/public/application/apps/context/services/anchor.test.ts +++ b/src/plugins/discover/public/application/apps/context/services/anchor.test.ts @@ -6,30 +6,29 @@ * Side Public License, v 1. */ -import { EsQuerySortValue, SortDirection } from '../../../../../../data/public'; -import { createIndexPatternsStub, createSearchSourceStub } from './_stubs'; -import { fetchAnchorProvider, updateSearchSource } from './anchor'; +import { IndexPattern, SortDirection } from '../../../../../../data/public'; +import { createSearchSourceStub } from './_stubs'; +import { fetchAnchor, updateSearchSource } from './anchor'; import { indexPatternMock } from '../../../../__mocks__/index_pattern'; import { savedSearchMock } from '../../../../__mocks__/saved_search'; -import { EsHitRecord, EsHitRecordList } from '../../../types'; +import { EsHitRecordList } from '../../../types'; describe('context app', function () { - let fetchAnchor: ( - indexPatternId: string, - anchorId: string, - sort: EsQuerySortValue[] - ) => Promise; // eslint-disable-next-line @typescript-eslint/no-explicit-any let searchSourceStub: any; + const indexPattern = { + id: 'INDEX_PATTERN_ID', + isTimeNanosBased: () => false, + popularizeField: () => {}, + } as unknown as IndexPattern; describe('function fetchAnchor', function () { beforeEach(() => { searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }] as unknown as EsHitRecordList); - fetchAnchor = fetchAnchorProvider(createIndexPatternsStub(), searchSourceStub); }); it('should use the `fetch` method of the SearchSource', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -38,7 +37,7 @@ describe('context app', function () { }); it('should configure the SearchSource to not inherit from the implicit root', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -49,7 +48,7 @@ describe('context app', function () { }); it('should set the SearchSource index pattern', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -59,7 +58,7 @@ describe('context app', function () { }); it('should set the SearchSource version flag to true', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -70,7 +69,7 @@ describe('context app', function () { }); it('should set the SearchSource size to 1', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -81,7 +80,7 @@ describe('context app', function () { }); it('should set the SearchSource query to an ids query', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -103,7 +102,7 @@ describe('context app', function () { }); it('should set the SearchSource sort order', function () { - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then(() => { @@ -145,7 +144,7 @@ describe('context app', function () { it('should reject with an error when no hits were found', function () { searchSourceStub._stubHits = []; - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then( @@ -161,7 +160,7 @@ describe('context app', function () { it('should return the first hit after adding an anchor marker', function () { searchSourceStub._stubHits = [{ property1: 'value1' }, { property2: 'value2' }]; - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ + return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then((anchorDocument) => { @@ -174,16 +173,18 @@ describe('context app', function () { describe('useNewFields API', () => { beforeEach(() => { searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }] as unknown as EsHitRecordList); - fetchAnchor = fetchAnchorProvider(createIndexPatternsStub(), searchSourceStub, true); }); it('should request fields if useNewFieldsApi set', function () { searchSourceStub._stubHits = [{ property1: 'value1' }, { property2: 'value2' }]; - return fetchAnchor('INDEX_PATTERN_ID', 'id', [ - { '@timestamp': SortDirection.desc }, - { _doc: SortDirection.desc }, - ]).then(() => { + return fetchAnchor( + 'id', + indexPattern, + searchSourceStub, + [{ '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }], + true + ).then(() => { const setFieldsSpy = searchSourceStub.setField.withArgs('fields'); const removeFieldsSpy = searchSourceStub.removeField.withArgs('fieldsFromSource'); expect(setFieldsSpy.calledOnce).toBe(true); diff --git a/src/plugins/discover/public/application/apps/context/services/anchor.ts b/src/plugins/discover/public/application/apps/context/services/anchor.ts index 2d64f7526ffdd..f262d440b8a28 100644 --- a/src/plugins/discover/public/application/apps/context/services/anchor.ts +++ b/src/plugins/discover/public/application/apps/context/services/anchor.ts @@ -6,46 +6,35 @@ * Side Public License, v 1. */ -import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - ISearchSource, - IndexPatternsContract, - EsQuerySortValue, - IndexPattern, -} from '../../../../../../data/public'; +import { ISearchSource, EsQuerySortValue, IndexPattern } from '../../../../../../data/public'; import { EsHitRecord } from '../../../types'; -export function fetchAnchorProvider( - indexPatterns: IndexPatternsContract, +export async function fetchAnchor( + anchorId: string, + indexPattern: IndexPattern, searchSource: ISearchSource, + sort: EsQuerySortValue[], useNewFieldsApi: boolean = false -) { - return async function fetchAnchor( - indexPatternId: string, - anchorId: string, - sort: EsQuerySortValue[] - ): Promise { - const indexPattern = await indexPatterns.get(indexPatternId); - updateSearchSource(searchSource, anchorId, sort, useNewFieldsApi, indexPattern); +): Promise { + updateSearchSource(searchSource, anchorId, sort, useNewFieldsApi, indexPattern); - const response = await searchSource.fetch(); - const doc = get(response, ['hits', 'hits', 0]); + const response = await searchSource.fetch(); + const doc = response.hits?.hits?.[0]; - if (!doc) { - throw new Error( - i18n.translate('discover.context.failedToLoadAnchorDocumentErrorDescription', { - defaultMessage: 'Failed to load anchor document.', - }) - ); - } + if (!doc) { + throw new Error( + i18n.translate('discover.context.failedToLoadAnchorDocumentErrorDescription', { + defaultMessage: 'Failed to load anchor document.', + }) + ); + } - return { - ...doc, - isAnchor: true, - } as EsHitRecord; - }; + return { + ...doc, + isAnchor: true, + } as EsHitRecord; } export function updateSearchSource( diff --git a/src/plugins/discover/public/application/apps/context/services/context.predecessors.test.ts b/src/plugins/discover/public/application/apps/context/services/context.predecessors.test.ts index 028dec7b9fe19..9bcf6f9c90d2c 100644 --- a/src/plugins/discover/public/application/apps/context/services/context.predecessors.test.ts +++ b/src/plugins/discover/public/application/apps/context/services/context.predecessors.test.ts @@ -8,9 +8,9 @@ import moment from 'moment'; import { get, last } from 'lodash'; -import { SortDirection } from 'src/plugins/data/common'; -import { createIndexPatternsStub, createContextSearchSourceStub } from './_stubs'; -import { fetchContextProvider, SurrDocType } from './context'; +import { IndexPattern, SortDirection } from 'src/plugins/data/common'; +import { createContextSearchSourceStub } from './_stubs'; +import { fetchSurroundingDocs, SurrDocType } from './context'; import { setServices } from '../../../../kibana_services'; import { Query } from '../../../../../../data/public'; import { DiscoverServices } from '../../../../build_services'; @@ -30,9 +30,6 @@ interface Timestamp { describe('context predecessors', function () { let fetchPredecessors: ( - indexPatternId: string, - timeField: string, - sortDir: SortDirection, timeValIso: string, timeValNr: number, tieBreakerField: string, @@ -41,6 +38,12 @@ describe('context predecessors', function () { ) => Promise; // eslint-disable-next-line @typescript-eslint/no-explicit-any let mockSearchSource: any; + const indexPattern = { + id: 'INDEX_PATTERN_ID', + timeFieldName: '@timestamp', + isTimeNanosBased: () => false, + popularizeField: () => {}, + } as unknown as IndexPattern; describe('function fetchPredecessors', function () { beforeEach(() => { @@ -56,30 +59,20 @@ describe('context predecessors', function () { }, } as unknown as DiscoverServices); - fetchPredecessors = ( - indexPatternId, - timeField, - sortDir, - timeValIso, - timeValNr, - tieBreakerField, - tieBreakerValue, - size = 10 - ) => { + fetchPredecessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size = 10) => { const anchor = { _source: { - [timeField]: timeValIso, + [indexPattern.timeFieldName!]: timeValIso, }, sort: [timeValNr, tieBreakerValue], }; - return fetchContextProvider(createIndexPatternsStub()).fetchSurroundingDocs( + return fetchSurroundingDocs( SurrDocType.PREDECESSORS, - indexPatternId, + indexPattern, anchor as EsHitRecord, - timeField, tieBreakerField, - sortDir, + SortDirection.desc, size, [] ); @@ -95,19 +88,12 @@ describe('context predecessors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 1000), ]; - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 3 - ).then((hits: EsHitRecordList) => { - expect(mockSearchSource.fetch.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); - }); + return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( + (hits: EsHitRecordList) => { + expect(mockSearchSource.fetch.calledOnce).toBe(true); + expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + } + ); }); it('should perform multiple queries with the last being unrestricted when too few hits are returned', function () { @@ -119,33 +105,26 @@ describe('context predecessors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 2990), ]; - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 6 - ).then((hits: EsHitRecordList) => { - const intervals: Timestamp[] = mockSearchSource.setField.args - .filter(([property]: string) => property === 'query') - .map(([, { query }]: [string, { query: Query }]) => - get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) - ); - - expect( - intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) - ).toBe(true); - // should have started at the given time - expect(intervals[0].gte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); - // should have ended with a half-open interval - expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'gte']); - expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); - }); + return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 6).then( + (hits: EsHitRecordList) => { + const intervals: Timestamp[] = mockSearchSource.setField.args + .filter(([property]: string) => property === 'query') + .map(([, { query }]: [string, { query: Query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); + + expect( + intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) + ).toBe(true); + // should have started at the given time + expect(intervals[0].gte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); + // should have ended with a half-open interval + expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'gte']); + expect(intervals.length).toBeGreaterThan(1); + + expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + } + ); }); it('should perform multiple queries until the expected hit count is returned', function () { @@ -156,57 +135,41 @@ describe('context predecessors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 1000), ]; - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_1000, - MS_PER_DAY * 1000, - '_doc', - 0, - 3 - ).then((hits: EsHitRecordList) => { - const intervals: Timestamp[] = mockSearchSource.setField.args - .filter(([property]: string) => property === 'query') - .map(([, { query }]: [string, { query: Query }]) => { - return get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']); - }); - - // should have started at the given time - expect(intervals[0].gte).toEqual(moment(MS_PER_DAY * 1000).toISOString()); - // should have stopped before reaching MS_PER_DAY * 1700 - expect(moment(last(intervals)?.lte).valueOf()).toBeLessThan(MS_PER_DAY * 1700); - expect(intervals.length).toBeGreaterThan(1); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); - }); + return fetchPredecessors(ANCHOR_TIMESTAMP_1000, MS_PER_DAY * 1000, '_doc', 0, 3).then( + (hits: EsHitRecordList) => { + const intervals: Timestamp[] = mockSearchSource.setField.args + .filter(([property]: string) => property === 'query') + .map(([, { query }]: [string, { query: Query }]) => { + return get(query, [ + 'bool', + 'must', + 'constant_score', + 'filter', + 'range', + '@timestamp', + ]); + }); + + // should have started at the given time + expect(intervals[0].gte).toEqual(moment(MS_PER_DAY * 1000).toISOString()); + // should have stopped before reaching MS_PER_DAY * 1700 + expect(moment(last(intervals)?.lte).valueOf()).toBeLessThan(MS_PER_DAY * 1700); + expect(intervals.length).toBeGreaterThan(1); + expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + } + ); }); it('should return an empty array when no hits were found', function () { - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3, - MS_PER_DAY * 3, - '_doc', - 0, - 3 - ).then((hits: EsHitRecordList) => { - expect(hits).toEqual([]); - }); + return fetchPredecessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then( + (hits: EsHitRecordList) => { + expect(hits).toEqual([]); + } + ); }); it('should configure the SearchSource to not inherit from the implicit root', function () { - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3, - MS_PER_DAY * 3, - '_doc', - 0, - 3 - ).then(() => { + return fetchPredecessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then(() => { const setParentSpy = mockSearchSource.setParent; expect(setParentSpy.alwaysCalledWith(undefined)).toBe(true); expect(setParentSpy.called).toBe(true); @@ -214,16 +177,7 @@ describe('context predecessors', function () { }); it('should set the tiebreaker sort order to the opposite as the time field', function () { - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP, - MS_PER_DAY, - '_doc', - 0, - 3 - ).then(() => { + return fetchPredecessors(ANCHOR_TIMESTAMP, MS_PER_DAY, '_doc', 0, 3).then(() => { expect( mockSearchSource.setField.calledWith('sort', [ { '@timestamp': { order: 'asc', format: 'strict_date_optional_time' } }, @@ -248,32 +202,23 @@ describe('context predecessors', function () { }, } as unknown as DiscoverServices); - fetchPredecessors = ( - indexPatternId, - timeField, - sortDir, - timeValIso, - timeValNr, - tieBreakerField, - tieBreakerValue, - size = 10 - ) => { + fetchPredecessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size = 10) => { const anchor = { _source: { - [timeField]: timeValIso, + [indexPattern.timeFieldName!]: timeValIso, }, sort: [timeValNr, tieBreakerValue], }; - return fetchContextProvider(createIndexPatternsStub(), true).fetchSurroundingDocs( + return fetchSurroundingDocs( SurrDocType.PREDECESSORS, - indexPatternId, + indexPattern, anchor as EsHitRecord, - timeField, tieBreakerField, - sortDir, + SortDirection.desc, size, - [] + [], + true ); }; }); @@ -287,23 +232,16 @@ describe('context predecessors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 1000), ]; - return fetchPredecessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 3 - ).then((hits: EsHitRecordList) => { - const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); - const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); - expect(mockSearchSource.fetch.calledOnce).toBe(true); - expect(removeFieldsSpy.calledOnce).toBe(true); - expect(setFieldsSpy.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); - }); + return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( + (hits: EsHitRecordList) => { + const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); + const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); + expect(mockSearchSource.fetch.calledOnce).toBe(true); + expect(removeFieldsSpy.calledOnce).toBe(true); + expect(setFieldsSpy.calledOnce).toBe(true); + expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + } + ); }); }); }); diff --git a/src/plugins/discover/public/application/apps/context/services/context.successors.test.ts b/src/plugins/discover/public/application/apps/context/services/context.successors.test.ts index 656491f01f9cf..169d969753645 100644 --- a/src/plugins/discover/public/application/apps/context/services/context.successors.test.ts +++ b/src/plugins/discover/public/application/apps/context/services/context.successors.test.ts @@ -8,11 +8,11 @@ import moment from 'moment'; import { get, last } from 'lodash'; -import { SortDirection } from 'src/plugins/data/common'; -import { createIndexPatternsStub, createContextSearchSourceStub } from './_stubs'; +import { IndexPattern, SortDirection } from 'src/plugins/data/common'; +import { createContextSearchSourceStub } from './_stubs'; import { setServices } from '../../../../kibana_services'; import { Query } from '../../../../../../data/public'; -import { fetchContextProvider, SurrDocType } from './context'; +import { fetchSurroundingDocs, SurrDocType } from './context'; import { DiscoverServices } from '../../../../build_services'; import { EsHitRecord, EsHitRecordList } from '../../../types'; @@ -29,9 +29,6 @@ interface Timestamp { describe('context successors', function () { let fetchSuccessors: ( - indexPatternId: string, - timeField: string, - sortDir: SortDirection, timeValIso: string, timeValNr: number, tieBreakerField: string, @@ -40,6 +37,12 @@ describe('context successors', function () { ) => Promise; // eslint-disable-next-line @typescript-eslint/no-explicit-any let mockSearchSource: any; + const indexPattern = { + id: 'INDEX_PATTERN_ID', + timeFieldName: '@timestamp', + isTimeNanosBased: () => false, + popularizeField: () => {}, + } as unknown as IndexPattern; describe('function fetchSuccessors', function () { beforeEach(() => { @@ -55,30 +58,20 @@ describe('context successors', function () { }, } as unknown as DiscoverServices); - fetchSuccessors = ( - indexPatternId, - timeField, - sortDir, - timeValIso, - timeValNr, - tieBreakerField, - tieBreakerValue, - size - ) => { + fetchSuccessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size) => { const anchor = { _source: { - [timeField]: timeValIso, + [indexPattern.timeFieldName!]: timeValIso, }, sort: [timeValNr, tieBreakerValue], }; - return fetchContextProvider(createIndexPatternsStub()).fetchSurroundingDocs( + return fetchSurroundingDocs( SurrDocType.SUCCESSORS, - indexPatternId, + indexPattern, anchor as EsHitRecord, - timeField, tieBreakerField, - sortDir, + SortDirection.desc, size, [] ); @@ -94,19 +87,12 @@ describe('context successors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 3000 - 2), ]; - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 3 - ).then((hits) => { - expect(mockSearchSource.fetch.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); - }); + return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( + (hits) => { + expect(mockSearchSource.fetch.calledOnce).toBe(true); + expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + } + ); }); it('should perform multiple queries with the last being unrestricted when too few hits are returned', function () { @@ -118,33 +104,26 @@ describe('context successors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 2990), ]; - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 6 - ).then((hits) => { - const intervals: Timestamp[] = mockSearchSource.setField.args - .filter(([property]: [string]) => property === 'query') - .map(([, { query }]: [string, { query: Query }]) => - get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) - ); - - expect( - intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) - ).toBe(true); - // should have started at the given time - expect(intervals[0].lte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); - // should have ended with a half-open interval - expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'lte']); - expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); - }); + return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 6).then( + (hits) => { + const intervals: Timestamp[] = mockSearchSource.setField.args + .filter(([property]: [string]) => property === 'query') + .map(([, { query }]: [string, { query: Query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); + + expect( + intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) + ).toBe(true); + // should have started at the given time + expect(intervals[0].lte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); + // should have ended with a half-open interval + expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'lte']); + expect(intervals.length).toBeGreaterThan(1); + + expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + } + ); }); it('should perform multiple queries until the expected hit count is returned', function () { @@ -157,58 +136,33 @@ describe('context successors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 1000), ]; - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 4 - ).then((hits) => { - const intervals: Timestamp[] = mockSearchSource.setField.args - .filter(([property]: [string]) => property === 'query') - .map(([, { query }]: [string, { query: Query }]) => - get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) - ); - - // should have started at the given time - expect(intervals[0].lte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); - // should have stopped before reaching MS_PER_DAY * 2200 - expect(moment(last(intervals)?.gte).valueOf()).toBeGreaterThan(MS_PER_DAY * 2200); - expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 4)); - }); + return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 4).then( + (hits) => { + const intervals: Timestamp[] = mockSearchSource.setField.args + .filter(([property]: [string]) => property === 'query') + .map(([, { query }]: [string, { query: Query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); + + // should have started at the given time + expect(intervals[0].lte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); + // should have stopped before reaching MS_PER_DAY * 2200 + expect(moment(last(intervals)?.gte).valueOf()).toBeGreaterThan(MS_PER_DAY * 2200); + expect(intervals.length).toBeGreaterThan(1); + + expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 4)); + } + ); }); it('should return an empty array when no hits were found', function () { - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3, - MS_PER_DAY * 3, - '_doc', - 0, - 3 - ).then((hits) => { + return fetchSuccessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then((hits) => { expect(hits).toEqual([]); }); }); it('should configure the SearchSource to not inherit from the implicit root', function () { - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3, - MS_PER_DAY * 3, - '_doc', - 0, - 3 - ).then(() => { + return fetchSuccessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then(() => { const setParentSpy = mockSearchSource.setParent; expect(setParentSpy.alwaysCalledWith(undefined)).toBe(true); expect(setParentSpy.called).toBe(true); @@ -216,16 +170,7 @@ describe('context successors', function () { }); it('should set the tiebreaker sort order to the same as the time field', function () { - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP, - MS_PER_DAY, - '_doc', - 0, - 3 - ).then(() => { + return fetchSuccessors(ANCHOR_TIMESTAMP, MS_PER_DAY, '_doc', 0, 3).then(() => { expect( mockSearchSource.setField.calledWith('sort', [ { '@timestamp': { order: SortDirection.desc, format: 'strict_date_optional_time' } }, @@ -250,32 +195,23 @@ describe('context successors', function () { }, } as unknown as DiscoverServices); - fetchSuccessors = ( - indexPatternId, - timeField, - sortDir, - timeValIso, - timeValNr, - tieBreakerField, - tieBreakerValue, - size - ) => { + fetchSuccessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size) => { const anchor = { _source: { - [timeField]: timeValIso, + [indexPattern.timeFieldName!]: timeValIso, }, sort: [timeValNr, tieBreakerValue], }; - return fetchContextProvider(createIndexPatternsStub(), true).fetchSurroundingDocs( + return fetchSurroundingDocs( SurrDocType.SUCCESSORS, - indexPatternId, + indexPattern, anchor as EsHitRecord, - timeField, tieBreakerField, - sortDir, + SortDirection.desc, size, - [] + [], + true ); }; }); @@ -289,23 +225,16 @@ describe('context successors', function () { mockSearchSource._createStubHit(MS_PER_DAY * 3000 - 2), ]; - return fetchSuccessors( - 'INDEX_PATTERN_ID', - '@timestamp', - SortDirection.desc, - ANCHOR_TIMESTAMP_3000, - MS_PER_DAY * 3000, - '_doc', - 0, - 3 - ).then((hits) => { - expect(mockSearchSource.fetch.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); - const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); - const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); - expect(removeFieldsSpy.calledOnce).toBe(true); - expect(setFieldsSpy.calledOnce).toBe(true); - }); + return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( + (hits) => { + expect(mockSearchSource.fetch.calledOnce).toBe(true); + expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); + const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); + expect(removeFieldsSpy.calledOnce).toBe(true); + expect(setFieldsSpy.calledOnce).toBe(true); + } + ); }); }); }); diff --git a/src/plugins/discover/public/application/apps/context/services/context.ts b/src/plugins/discover/public/application/apps/context/services/context.ts index 237de8e52e656..b76b5ac648c22 100644 --- a/src/plugins/discover/public/application/apps/context/services/context.ts +++ b/src/plugins/discover/public/application/apps/context/services/context.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { Filter, IndexPattern, IndexPatternsContract, SearchSource } from 'src/plugins/data/public'; +import { Filter, IndexPattern, SearchSource } from 'src/plugins/data/public'; import { reverseSortDir, SortDirection } from './utils/sorting'; import { convertIsoToMillis, extractNanos } from './utils/date_conversion'; import { fetchHitsInInterval } from './utils/fetch_hits_in_interval'; @@ -25,88 +25,82 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000; // look from 1 day up to 10000 days into the past and future const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map((days) => days * DAY_MILLIS); -function fetchContextProvider(indexPatterns: IndexPatternsContract, useNewFieldsApi?: boolean) { - return { - fetchSurroundingDocs, - }; - - /** - * Fetch successor or predecessor documents of a given anchor document - * - * @param {SurrDocType} type - `successors` or `predecessors` - * @param {string} indexPatternId - * @param {EsHitRecord} anchor - anchor record - * @param {string} timeField - name of the timefield, that's sorted on - * @param {string} tieBreakerField - name of the tie breaker, the 2nd sort field - * @param {SortDirection} sortDir - direction of sorting - * @param {number} size - number of records to retrieve - * @param {Filter[]} filters - to apply in the elastic query - * @returns {Promise} - */ - async function fetchSurroundingDocs( - type: SurrDocType, - indexPatternId: string, - anchor: EsHitRecord, - timeField: string, - tieBreakerField: string, - sortDir: SortDirection, - size: number, - filters: Filter[] - ): Promise { - if (typeof anchor !== 'object' || anchor === null || !size) { - return []; - } - const indexPattern = await indexPatterns.get(indexPatternId); - const { data } = getServices(); - const searchSource = data.search.searchSource.createEmpty() as SearchSource; - updateSearchSource(searchSource, indexPattern, filters, Boolean(useNewFieldsApi)); - const sortDirToApply = type === SurrDocType.SUCCESSORS ? sortDir : reverseSortDir(sortDir); - - const nanos = indexPattern.isTimeNanosBased() ? extractNanos(anchor.fields[timeField][0]) : ''; - const timeValueMillis = - nanos !== '' ? convertIsoToMillis(anchor.fields[timeField][0]) : anchor.sort[0]; - - const intervals = generateIntervals(LOOKUP_OFFSETS, timeValueMillis as number, type, sortDir); - let documents: EsHitRecordList = []; - - for (const interval of intervals) { - const remainingSize = size - documents.length; - - if (remainingSize <= 0) { - break; - } +/** + * Fetch successor or predecessor documents of a given anchor document + * + * @param {SurrDocType} type - `successors` or `predecessors` + * @param {IndexPattern} indexPattern + * @param {EsHitRecord} anchor - anchor record + * @param {string} tieBreakerField - name of the tie breaker, the 2nd sort field + * @param {SortDirection} sortDir - direction of sorting + * @param {number} size - number of records to retrieve + * @param {Filter[]} filters - to apply in the elastic query + * @param {boolean} useNewFieldsApi + * @returns {Promise} + */ +export async function fetchSurroundingDocs( + type: SurrDocType, + indexPattern: IndexPattern, + anchor: EsHitRecord, + tieBreakerField: string, + sortDir: SortDirection, + size: number, + filters: Filter[], + useNewFieldsApi?: boolean +): Promise { + if (typeof anchor !== 'object' || anchor === null || !size) { + return []; + } + const { data } = getServices(); + const timeField = indexPattern.timeFieldName!; + const searchSource = data.search.searchSource.createEmpty() as SearchSource; + updateSearchSource(searchSource, indexPattern, filters, Boolean(useNewFieldsApi)); + const sortDirToApply = type === SurrDocType.SUCCESSORS ? sortDir : reverseSortDir(sortDir); - const searchAfter = getEsQuerySearchAfter( - type, - documents, - timeField, - anchor, - nanos, - useNewFieldsApi - ); + const nanos = indexPattern.isTimeNanosBased() ? extractNanos(anchor.fields[timeField][0]) : ''; + const timeValueMillis = + nanos !== '' ? convertIsoToMillis(anchor.fields[timeField][0]) : anchor.sort[0]; - const sort = getEsQuerySort(timeField, tieBreakerField, sortDirToApply, nanos); + const intervals = generateIntervals(LOOKUP_OFFSETS, timeValueMillis as number, type, sortDir); + let documents: EsHitRecordList = []; - const hits = await fetchHitsInInterval( - searchSource, - timeField, - sort, - sortDirToApply, - interval, - searchAfter, - remainingSize, - nanos, - anchor._id - ); + for (const interval of intervals) { + const remainingSize = size - documents.length; - documents = - type === SurrDocType.SUCCESSORS - ? [...documents, ...hits] - : [...hits.slice().reverse(), ...documents]; + if (remainingSize <= 0) { + break; } - return documents; + const searchAfter = getEsQuerySearchAfter( + type, + documents, + timeField, + anchor, + nanos, + useNewFieldsApi + ); + + const sort = getEsQuerySort(timeField, tieBreakerField, sortDirToApply, nanos); + + const hits = await fetchHitsInInterval( + searchSource, + timeField, + sort, + sortDirToApply, + interval, + searchAfter, + remainingSize, + nanos, + anchor._id + ); + + documents = + type === SurrDocType.SUCCESSORS + ? [...documents, ...hits] + : [...hits.slice().reverse(), ...documents]; } + + return documents; } export function updateSearchSource( @@ -125,5 +119,3 @@ export function updateSearchSource( .setField('filter', filters) .setField('trackTotalHits', false); } - -export { fetchContextProvider }; diff --git a/src/plugins/discover/public/application/apps/context/services/context_state.test.ts b/src/plugins/discover/public/application/apps/context/services/context_state.test.ts index 3e5acccff634e..3df8ab710729f 100644 --- a/src/plugins/discover/public/application/apps/context/services/context_state.test.ts +++ b/src/plugins/discover/public/application/apps/context/services/context_state.test.ts @@ -24,7 +24,6 @@ describe('Test Discover Context State', () => { history.push('/'); state = getState({ defaultSize: 4, - timeFieldName: 'time', history, uiSettings: { get: (key: string) => @@ -44,12 +43,6 @@ describe('Test Discover Context State', () => { ], "filters": Array [], "predecessorCount": 4, - "sort": Array [ - Array [ - "time", - "desc", - ], - ], "successorCount": 4, } `); @@ -62,41 +55,29 @@ describe('Test Discover Context State', () => { state.setAppState({ predecessorCount: 10 }); state.flushToUrl(); expect(getCurrentUrl()).toMatchInlineSnapshot( - `"/#?_a=(columns:!(_source),filters:!(),predecessorCount:10,sort:!(!(time,desc)),successorCount:4)"` + `"/#?_a=(columns:!(_source),filters:!(),predecessorCount:10,successorCount:4)"` ); }); test('getState -> url to appState syncing', async () => { - history.push( - '/#?_a=(columns:!(_source),predecessorCount:1,sort:!(time,desc),successorCount:1)' - ); + history.push('/#?_a=(columns:!(_source),predecessorCount:1,successorCount:1)'); expect(state.appState.getState()).toMatchInlineSnapshot(` Object { "columns": Array [ "_source", ], "predecessorCount": 1, - "sort": Array [ - "time", - "desc", - ], "successorCount": 1, } `); }); test('getState -> url to appState syncing with return to a url without state', async () => { - history.push( - '/#?_a=(columns:!(_source),predecessorCount:1,sort:!(time,desc),successorCount:1)' - ); + history.push('/#?_a=(columns:!(_source),predecessorCount:1,successorCount:1)'); expect(state.appState.getState()).toMatchInlineSnapshot(` Object { "columns": Array [ "_source", ], "predecessorCount": 1, - "sort": Array [ - "time", - "desc", - ], "successorCount": 1, } `); @@ -107,10 +88,6 @@ describe('Test Discover Context State', () => { "_source", ], "predecessorCount": 1, - "sort": Array [ - "time", - "desc", - ], "successorCount": 1, } `); @@ -183,7 +160,7 @@ describe('Test Discover Context State', () => { `); state.flushToUrl(); expect(getCurrentUrl()).toMatchInlineSnapshot( - `"/#?_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,index:'logstash-*',key:extension,negate:!f,params:(query:jpg),type:phrase),query:(match_phrase:(extension:(query:jpg))))))&_a=(columns:!(_source),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:'logstash-*',key:extension,negate:!t,params:(query:png),type:phrase),query:(match_phrase:(extension:(query:png))))),predecessorCount:4,sort:!(!(time,desc)),successorCount:4)"` + `"/#?_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,index:'logstash-*',key:extension,negate:!f,params:(query:jpg),type:phrase),query:(match_phrase:(extension:(query:jpg))))))&_a=(columns:!(_source),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:'logstash-*',key:extension,negate:!t,params:(query:png),type:phrase),query:(match_phrase:(extension:(query:png))))),predecessorCount:4,successorCount:4)"` ); }); }); diff --git a/src/plugins/discover/public/application/apps/context/services/context_state.ts b/src/plugins/discover/public/application/apps/context/services/context_state.ts index 582ca196e3484..87f7cf00bafcf 100644 --- a/src/plugins/discover/public/application/apps/context/services/context_state.ts +++ b/src/plugins/discover/public/application/apps/context/services/context_state.ts @@ -16,7 +16,7 @@ import { withNotifyOnErrors, ReduxLikeStateContainer, } from '../../../../../../kibana_utils/public'; -import { esFilters, FilterManager, Filter, SortDirection } from '../../../../../../data/public'; +import { esFilters, FilterManager, Filter } from '../../../../../../data/public'; import { handleSourceColumnState } from '../../../helpers/state_helpers'; export interface AppState { @@ -32,14 +32,16 @@ export interface AppState { * Number of records to be fetched before anchor records (newer records) */ predecessorCount: number; - /** - * Sorting of the records to be fetched, assumed to be a legacy parameter - */ - sort: string[][]; /** * Number of records to be fetched after the anchor records (older records) */ successorCount: number; + /** + * Array of the used sorting [[field,direction],...] + * this is actually not needed in Discover Context, there's no sorting + * but it's used in the DocTable component + */ + sort?: string[][]; } interface GlobalState { @@ -54,10 +56,6 @@ export interface GetStateParams { * Number of records to be fetched when 'Load' link/button is clicked */ defaultSize: number; - /** - * The timefield used for sorting - */ - timeFieldName: string; /** * Determins the use of long vs. short/hashed urls */ @@ -124,7 +122,6 @@ const APP_STATE_URL_KEY = '_a'; */ export function getState({ defaultSize, - timeFieldName, storeInSessionStorage = false, history, toasts, @@ -140,12 +137,7 @@ export function getState({ const globalStateContainer = createStateContainer(globalStateInitial); const appStateFromUrl = stateStorage.get(APP_STATE_URL_KEY) as AppState; - const appStateInitial = createInitialAppState( - defaultSize, - timeFieldName, - appStateFromUrl, - uiSettings - ); + const appStateInitial = createInitialAppState(defaultSize, appStateFromUrl, uiSettings); const appStateContainer = createStateContainer(appStateInitial); const { start, stop } = syncStates([ @@ -267,7 +259,6 @@ function getFilters(state: AppState | GlobalState): Filter[] { */ function createInitialAppState( defaultSize: number, - timeFieldName: string, urlState: AppState, uiSettings: IUiSettingsClient ): AppState { @@ -276,7 +267,6 @@ function createInitialAppState( filters: [], predecessorCount: defaultSize, successorCount: defaultSize, - sort: [[timeFieldName, SortDirection.desc]], }; if (typeof urlState !== 'object') { return defaultState; diff --git a/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.test.ts b/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.test.ts index 5efd5e1195c5d..b3626f9c06f10 100644 --- a/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.test.ts +++ b/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.test.ts @@ -8,12 +8,9 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { setServices, getServices } from '../../../../kibana_services'; -import { SortDirection } from '../../../../../../data/public'; import { createFilterManagerMock } from '../../../../../../data/public/query/filter_manager/filter_manager.mock'; import { CONTEXT_TIE_BREAKER_FIELDS_SETTING } from '../../../../../common'; import { DiscoverServices } from '../../../../build_services'; -import { indexPatternMock } from '../../../../__mocks__/index_pattern'; -import { indexPatternsMock } from '../../../../__mocks__/index_patterns'; import { FailureReason, LoadingStatus } from '../services/context_query_state'; import { ContextAppFetchProps, useContextAppFetch } from './use_context_app_fetch'; import { @@ -21,6 +18,9 @@ import { mockPredecessorHits, mockSuccessorHits, } from '../__mocks__/use_context_app_fetch'; +import { indexPatternWithTimefieldMock } from '../../../../__mocks__/index_pattern_with_timefield'; +import { createContextSearchSourceStub } from '../services/_stubs'; +import { IndexPattern } from '../../../../../../data_views/common'; const mockFilterManager = createFilterManagerMock(); @@ -28,20 +28,19 @@ jest.mock('../services/context', () => { const originalModule = jest.requireActual('../services/context'); return { ...originalModule, - fetchContextProvider: () => ({ - fetchSurroundingDocs: (type: string, indexPatternId: string) => { - if (!indexPatternId) { - throw new Error(); - } - return type === 'predecessors' ? mockPredecessorHits : mockSuccessorHits; - }, - }), + + fetchSurroundingDocs: (type: string, indexPattern: IndexPattern) => { + if (!indexPattern || !indexPattern.id) { + throw new Error(); + } + return type === 'predecessors' ? mockPredecessorHits : mockSuccessorHits; + }, }; }); jest.mock('../services/anchor', () => ({ - fetchAnchorProvider: () => (indexPatternId: string) => { - if (!indexPatternId) { + fetchAnchor: (anchorId: string, indexPattern: IndexPattern) => { + if (!indexPattern.id || !anchorId) { throw new Error(); } return mockAnchorHit; @@ -50,16 +49,16 @@ jest.mock('../services/anchor', () => ({ const initDefaults = (tieBreakerFields: string[], indexPatternId = 'the-index-pattern-id') => { const dangerNotification = jest.fn(); + const mockSearchSource = createContextSearchSourceStub('timestamp'); setServices({ data: { search: { searchSource: { - createEmpty: jest.fn(), + createEmpty: jest.fn().mockImplementation(() => mockSearchSource), }, }, }, - indexPatterns: indexPatternsMock, toastNotifications: { addDanger: dangerNotification }, core: { notifications: { toasts: [] } }, history: () => {}, @@ -77,10 +76,8 @@ const initDefaults = (tieBreakerFields: string[], indexPatternId = 'the-index-pa dangerNotification, props: { anchorId: 'mock_anchor_id', - indexPatternId, - indexPattern: indexPatternMock, + indexPattern: { ...indexPatternWithTimefieldMock, id: indexPatternId }, appState: { - sort: [['order_date', SortDirection.desc]], predecessorCount: 2, successorCount: 2, }, diff --git a/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.tsx b/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.tsx index fa6a761397335..ed3b4e8ed5b5a 100644 --- a/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.tsx +++ b/src/plugins/discover/public/application/apps/context/utils/use_context_app_fetch.tsx @@ -7,11 +7,10 @@ */ import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { fromPairs } from 'lodash'; import { CONTEXT_TIE_BREAKER_FIELDS_SETTING } from '../../../../../common'; import { DiscoverServices } from '../../../../build_services'; -import { fetchAnchorProvider } from '../services/anchor'; -import { fetchContextProvider, SurrDocType } from '../services/context'; +import { fetchAnchor } from '../services/anchor'; +import { fetchSurroundingDocs, SurrDocType } from '../services/context'; import { MarkdownSimple, toMountPoint } from '../../../../../../kibana_react/public'; import { IndexPattern, SortDirection } from '../../../../../../data/public'; import { @@ -30,7 +29,6 @@ const createError = (statusKey: string, reason: FailureReason, error?: Error) => export interface ContextAppFetchProps { anchorId: string; - indexPatternId: string; indexPattern: IndexPattern; appState: AppState; useNewFieldsApi: boolean; @@ -39,13 +37,12 @@ export interface ContextAppFetchProps { export function useContextAppFetch({ anchorId, - indexPatternId, indexPattern, appState, useNewFieldsApi, services, }: ContextAppFetchProps) { - const { uiSettings: config, data, indexPatterns, toastNotifications, filterManager } = services; + const { uiSettings: config, data, toastNotifications, filterManager } = services; const searchSource = useMemo(() => { return data.search.searchSource.createEmpty(); @@ -54,13 +51,6 @@ export function useContextAppFetch({ () => getFirstSortableField(indexPattern, config.get(CONTEXT_TIE_BREAKER_FIELDS_SETTING)), [config, indexPattern] ); - const fetchAnchor = useMemo(() => { - return fetchAnchorProvider(indexPatterns, searchSource, useNewFieldsApi); - }, [indexPatterns, searchSource, useNewFieldsApi]); - const { fetchSurroundingDocs } = useMemo( - () => fetchContextProvider(indexPatterns, useNewFieldsApi), - [indexPatterns, useNewFieldsApi] - ); const [fetchedState, setFetchedState] = useState( getInitialContextQueryState() @@ -71,8 +61,6 @@ export function useContextAppFetch({ }, []); const fetchAnchorRow = useCallback(async () => { - const { sort } = appState; - const [[, sortDir]] = sort; const errorTitle = i18n.translate('discover.context.unableToLoadAnchorDocumentDescription', { defaultMessage: 'Unable to load the anchor document', }); @@ -94,10 +82,11 @@ export function useContextAppFetch({ try { setState({ anchorStatus: { value: LoadingStatus.LOADING } }); - const anchor = await fetchAnchor(indexPatternId, anchorId, [ - fromPairs(sort), - { [tieBreakerField]: sortDir }, - ]); + const sort = [ + { [indexPattern.timeFieldName!]: SortDirection.desc }, + { [tieBreakerField]: SortDirection.desc }, + ]; + const anchor = await fetchAnchor(anchorId, indexPattern, searchSource, sort, useNewFieldsApi); setState({ anchor, anchorStatus: { value: LoadingStatus.LOADED } }); return anchor; } catch (error) { @@ -108,20 +97,18 @@ export function useContextAppFetch({ }); } }, [ - appState, tieBreakerField, setState, toastNotifications, - fetchAnchor, - indexPatternId, + indexPattern, anchorId, + searchSource, + useNewFieldsApi, ]); const fetchSurroundingRows = useCallback( async (type: SurrDocType, fetchedAnchor?: EsHitRecord) => { const filters = filterManager.getFilters(); - const { sort } = appState; - const [[sortField, sortDir]] = sort; const count = type === SurrDocType.PREDECESSORS ? appState.predecessorCount : appState.successorCount; @@ -135,13 +122,13 @@ export function useContextAppFetch({ setState({ [statusKey]: { value: LoadingStatus.LOADING } }); const rows = await fetchSurroundingDocs( type, - indexPatternId, + indexPattern, anchor as EsHitRecord, - sortField, tieBreakerField, - sortDir as SortDirection, + SortDirection.desc, count, - filters + filters, + useNewFieldsApi ); setState({ [type]: rows, [statusKey]: { value: LoadingStatus.LOADED } }); } catch (error) { @@ -158,9 +145,9 @@ export function useContextAppFetch({ fetchedState.anchor, tieBreakerField, setState, - fetchSurroundingDocs, - indexPatternId, + indexPattern, toastNotifications, + useNewFieldsApi, ] ); diff --git a/src/plugins/discover/public/application/apps/context/utils/use_context_app_state.ts b/src/plugins/discover/public/application/apps/context/utils/use_context_app_state.ts index 3e968b5dfb82e..56701f17c7a63 100644 --- a/src/plugins/discover/public/application/apps/context/utils/use_context_app_state.ts +++ b/src/plugins/discover/public/application/apps/context/utils/use_context_app_state.ts @@ -9,29 +9,21 @@ import { useEffect, useMemo, useState } from 'react'; import { cloneDeep } from 'lodash'; import { CONTEXT_DEFAULT_SIZE_SETTING } from '../../../../../common'; -import { IndexPattern } from '../../../../../../data/public'; import { DiscoverServices } from '../../../../build_services'; import { AppState, getState } from '../services/context_state'; -export function useContextAppState({ - indexPattern, - services, -}: { - indexPattern: IndexPattern; - services: DiscoverServices; -}) { +export function useContextAppState({ services }: { services: DiscoverServices }) { const { uiSettings: config, history, core, filterManager } = services; const stateContainer = useMemo(() => { return getState({ defaultSize: parseInt(config.get(CONTEXT_DEFAULT_SIZE_SETTING), 10), - timeFieldName: indexPattern.timeFieldName!, storeInSessionStorage: config.get('state:storeInSessionStorage'), history: history(), toasts: core.notifications.toasts, uiSettings: config, }); - }, [config, history, indexPattern, core.notifications.toasts]); + }, [config, history, core.notifications.toasts]); const [appState, setState] = useState(stateContainer.appState.getState()); From c3f1e0de541901679de4cb7b2317b5b1f6b58e4f Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 12 Oct 2021 14:35:45 +0200 Subject: [PATCH 45/73] [FieldFormats] Remove SerializedFieldFormat copy from expressions plugin (#114245) --- src/plugins/data/common/search/aggs/agg_config.ts | 7 ++----- src/plugins/data/common/search/aggs/agg_type.ts | 3 ++- .../data/common/search/aggs/utils/get_aggs_formats.ts | 2 +- src/plugins/data_views/common/data_views/data_view.ts | 7 +++++-- src/plugins/data_views/common/types.ts | 3 +-- .../apps/main/components/chart/point_series.ts | 2 +- .../common/expression_types/specs/datatable.ts | 2 +- src/plugins/expressions/common/types/common.ts | 11 ----------- src/plugins/expressions/common/types/index.ts | 8 +------- src/plugins/expressions/public/index.ts | 1 - src/plugins/expressions/server/index.ts | 1 - src/plugins/expressions/tsconfig.json | 1 + src/plugins/vis_types/pie/public/types/types.ts | 3 ++- .../common/expression_functions/xy_dimension.ts | 2 +- src/plugins/visualizations/public/vis_schemas.ts | 2 +- x-pack/plugins/lens/common/types.ts | 7 +++++-- .../public/xy_visualization/axes_configuration.ts | 7 +++++-- 17 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/plugins/data/common/search/aggs/agg_config.ts b/src/plugins/data/common/search/aggs/agg_config.ts index 1a70a41e72dd5..4cb091787c058 100644 --- a/src/plugins/data/common/search/aggs/agg_config.ts +++ b/src/plugins/data/common/search/aggs/agg_config.ts @@ -13,11 +13,8 @@ import type { SerializableRecord } from '@kbn/utility-types'; import { Assign, Ensure } from '@kbn/utility-types'; import { ISearchOptions, ISearchSource } from 'src/plugins/data/public'; -import { - ExpressionAstExpression, - ExpressionAstArgument, - SerializedFieldFormat, -} from 'src/plugins/expressions/common'; +import { ExpressionAstExpression, ExpressionAstArgument } from 'src/plugins/expressions/common'; +import type { SerializedFieldFormat } from 'src/plugins/field_formats/common'; import { IAggType } from './agg_type'; import { writeParams } from './agg_params'; diff --git a/src/plugins/data/common/search/aggs/agg_type.ts b/src/plugins/data/common/search/aggs/agg_type.ts index 48ce54bbd61bd..ebc1705f6c01b 100644 --- a/src/plugins/data/common/search/aggs/agg_type.ts +++ b/src/plugins/data/common/search/aggs/agg_type.ts @@ -10,8 +10,9 @@ import { constant, noop, identity } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ISearchSource } from 'src/plugins/data/public'; -import { DatatableColumnType, SerializedFieldFormat } from 'src/plugins/expressions/common'; +import { DatatableColumnType } from 'src/plugins/expressions/common'; import type { RequestAdapter } from 'src/plugins/inspector/common'; +import type { SerializedFieldFormat } from 'src/plugins/field_formats/common'; import { estypes } from '@elastic/elasticsearch'; import { initParams } from './agg_params'; diff --git a/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts index 2aead866c6b60..1652f51477e64 100644 --- a/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts +++ b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts @@ -9,12 +9,12 @@ /* eslint-disable max-classes-per-file */ import { i18n } from '@kbn/i18n'; -import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; import { FieldFormat, FieldFormatInstanceType, FieldFormatsContentType, IFieldFormat, + SerializedFieldFormat, } from '../../../../../field_formats/common'; import { DateRange } from '../../expressions'; import { convertDateRangeToString } from '../buckets/lib/date_range'; diff --git a/src/plugins/data_views/common/data_views/data_view.ts b/src/plugins/data_views/common/data_views/data_view.ts index 00b96cda32ad7..5768ebe635729 100644 --- a/src/plugins/data_views/common/data_views/data_view.ts +++ b/src/plugins/data_views/common/data_views/data_view.ts @@ -19,9 +19,12 @@ import { IIndexPattern, IFieldType } from '../../common'; import { DataViewField, IIndexPatternFieldList, fieldList } from '../fields'; import { formatHitProvider } from './format_hit'; import { flattenHitWrapper } from './flatten_hit'; -import { FieldFormatsStartCommon, FieldFormat } from '../../../field_formats/common'; +import { + FieldFormatsStartCommon, + FieldFormat, + SerializedFieldFormat, +} from '../../../field_formats/common'; import { DataViewSpec, TypeMeta, SourceFilter, DataViewFieldMap } from '../types'; -import { SerializedFieldFormat } from '../../../expressions/common'; interface DataViewDeps { spec?: DataViewSpec; diff --git a/src/plugins/data_views/common/types.ts b/src/plugins/data_views/common/types.ts index 2b184bc1ef2a4..bbc5ad374636f 100644 --- a/src/plugins/data_views/common/types.ts +++ b/src/plugins/data_views/common/types.ts @@ -13,9 +13,8 @@ import type { SavedObject } from 'src/core/server'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { IFieldType } from './fields'; import { RUNTIME_FIELD_TYPES } from './constants'; -import { SerializedFieldFormat } from '../../expressions/common'; import { DataViewField } from './fields'; -import { FieldFormat } from '../../field_formats/common'; +import { FieldFormat, SerializedFieldFormat } from '../../field_formats/common'; export type FieldFormatMap = Record; diff --git a/src/plugins/discover/public/application/apps/main/components/chart/point_series.ts b/src/plugins/discover/public/application/apps/main/components/chart/point_series.ts index 1245b712e6fd7..ee057fcb48c6a 100644 --- a/src/plugins/discover/public/application/apps/main/components/chart/point_series.ts +++ b/src/plugins/discover/public/application/apps/main/components/chart/point_series.ts @@ -9,7 +9,7 @@ import { uniq } from 'lodash'; import { Duration, Moment } from 'moment'; import { Unit } from '@elastic/datemath'; -import { SerializedFieldFormat } from '../../../../../../../expressions/common'; +import type { SerializedFieldFormat } from '../../../../../../../field_formats/common'; export interface Column { id: string; diff --git a/src/plugins/expressions/common/expression_types/specs/datatable.ts b/src/plugins/expressions/common/expression_types/specs/datatable.ts index b45c36950f870..a07f103d12e06 100644 --- a/src/plugins/expressions/common/expression_types/specs/datatable.ts +++ b/src/plugins/expressions/common/expression_types/specs/datatable.ts @@ -8,11 +8,11 @@ import type { SerializableRecord } from '@kbn/utility-types'; import { map, pick, zipObject } from 'lodash'; +import type { SerializedFieldFormat } from 'src/plugins/field_formats/common'; import { ExpressionTypeDefinition, ExpressionValueBoxed } from '../types'; import { PointSeries, PointSeriesColumn } from './pointseries'; import { ExpressionValueRender } from './render'; -import { SerializedFieldFormat } from '../../types'; const name = 'datatable'; diff --git a/src/plugins/expressions/common/types/common.ts b/src/plugins/expressions/common/types/common.ts index 64b3d00895f56..b28ff27a79ac1 100644 --- a/src/plugins/expressions/common/types/common.ts +++ b/src/plugins/expressions/common/types/common.ts @@ -46,14 +46,3 @@ export type TypeString = KnownTypeToString< * `date` is typed as a number or string, and represents a date */ export type UnmappedTypeStrings = 'date' | 'filter'; - -/** - * JSON representation of a field formatter configuration. - * Is used to carry information about how to format data in - * a data table as part of the column definition. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export interface SerializedFieldFormat> { - id?: string; - params?: TParams; -} diff --git a/src/plugins/expressions/common/types/index.ts b/src/plugins/expressions/common/types/index.ts index 7d672df2401ff..00a79289c0b5f 100644 --- a/src/plugins/expressions/common/types/index.ts +++ b/src/plugins/expressions/common/types/index.ts @@ -6,13 +6,7 @@ * Side Public License, v 1. */ -export { - TypeToString, - KnownTypeToString, - TypeString, - UnmappedTypeStrings, - SerializedFieldFormat, -} from './common'; +export { TypeToString, KnownTypeToString, TypeString, UnmappedTypeStrings } from './common'; export * from './style'; export * from './registry'; diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 02656943cac3e..6e8d220a3ca0c 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -97,7 +97,6 @@ export { PointSeriesRow, Range, SerializedDatatable, - SerializedFieldFormat, Style, TextAlignment, TextDecoration, diff --git a/src/plugins/expressions/server/index.ts b/src/plugins/expressions/server/index.ts index c09a8bf0104af..7c0662ad54e4b 100644 --- a/src/plugins/expressions/server/index.ts +++ b/src/plugins/expressions/server/index.ts @@ -88,7 +88,6 @@ export { PointSeriesRow, Range, SerializedDatatable, - SerializedFieldFormat, Style, TextAlignment, TextDecoration, diff --git a/src/plugins/expressions/tsconfig.json b/src/plugins/expressions/tsconfig.json index 6716149d6b9c7..d9991ff791e83 100644 --- a/src/plugins/expressions/tsconfig.json +++ b/src/plugins/expressions/tsconfig.json @@ -11,5 +11,6 @@ { "path": "../../core/tsconfig.json" }, { "path": "../kibana_utils/tsconfig.json" }, { "path": "../inspector/tsconfig.json" }, + { "path": "../field_formats/tsconfig.json" } ] } diff --git a/src/plugins/vis_types/pie/public/types/types.ts b/src/plugins/vis_types/pie/public/types/types.ts index a1f41e80fae28..fb5efb5971805 100644 --- a/src/plugins/vis_types/pie/public/types/types.ts +++ b/src/plugins/vis_types/pie/public/types/types.ts @@ -8,7 +8,8 @@ import { Position } from '@elastic/charts'; import { UiCounterMetricType } from '@kbn/analytics'; -import { DatatableColumn, SerializedFieldFormat } from '../../../../expressions/public'; +import { DatatableColumn } from '../../../../expressions/public'; +import type { SerializedFieldFormat } from '../../../../field_formats/common'; import { ExpressionValueVisDimension } from '../../../../visualizations/public'; import { ExpressionValuePieLabels } from '../expression_functions/pie_labels'; import { PaletteOutput, ChartsPluginSetup } from '../../../../charts/public'; diff --git a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts index 82538fea8605a..5bbddd48e9b8b 100644 --- a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts +++ b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts @@ -14,8 +14,8 @@ import type { ExpressionValueBoxed, Datatable, DatatableColumn, - SerializedFieldFormat, } from '../../../expressions/common'; +import type { SerializedFieldFormat } from '../../../field_formats/common'; export interface DateHistogramParams { date: boolean; diff --git a/src/plugins/visualizations/public/vis_schemas.ts b/src/plugins/visualizations/public/vis_schemas.ts index 115e13ece45ff..f80f85fb55a60 100644 --- a/src/plugins/visualizations/public/vis_schemas.ts +++ b/src/plugins/visualizations/public/vis_schemas.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { SerializedFieldFormat } from '../../expressions/public'; +import type { SerializedFieldFormat } from '../../field_formats/common'; import { IAggConfig, search } from '../../data/public'; import { Vis, VisToExpressionAstParams } from './types'; diff --git a/x-pack/plugins/lens/common/types.ts b/x-pack/plugins/lens/common/types.ts index 79450b76190fb..659d3c0eced26 100644 --- a/x-pack/plugins/lens/common/types.ts +++ b/x-pack/plugins/lens/common/types.ts @@ -6,8 +6,11 @@ */ import type { Filter, FilterMeta } from '@kbn/es-query'; -import type { IFieldFormat } from '../../../../src/plugins/field_formats/common'; -import type { Datatable, SerializedFieldFormat } from '../../../../src/plugins/expressions/common'; +import type { + IFieldFormat, + SerializedFieldFormat, +} from '../../../../src/plugins/field_formats/common'; +import type { Datatable } from '../../../../src/plugins/expressions/common'; export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; diff --git a/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts b/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts index 9c83e2c58146e..9ac0171a51084 100644 --- a/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts +++ b/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts @@ -7,8 +7,11 @@ import { FormatFactory } from '../../common'; import { AxisExtentConfig, XYLayerConfig } from '../../common/expressions'; -import { Datatable, SerializedFieldFormat } from '../../../../../src/plugins/expressions/public'; -import type { IFieldFormat } from '../../../../../src/plugins/field_formats/common'; +import { Datatable } from '../../../../../src/plugins/expressions/public'; +import type { + IFieldFormat, + SerializedFieldFormat, +} from '../../../../../src/plugins/field_formats/common'; interface FormattedMetric { layer: string; From 4436ed2f7127f1bb31d9ee6fdc0dae54c889ccd5 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Tue, 12 Oct 2021 09:20:11 -0400 Subject: [PATCH 46/73] [Security Solution][Endpoint] Bug fixes and unit test cases for the Trusted Apps list view under Policy Details (#113865) * test: rename mock utility * Tests: artifact grid test coverage * Fix: CardCompressedHeader should use CardCompressedHeaderLayout * Tests: ArtifactEntryCollapsibleCard test coverage * Context Menu adjustments to test ids and to avoid react console errors/warnings * add test id to truncate wrapper in ContextMenuItemWithRouterSupport * Tests for ContextMenuWithRouterSupport * new mocks test utils * HTTP mocks for Policy Details Trusted apps list page * tests for policy trusted apps selectors * Refactor: move reusable fleet http mocks to `page/mocks` * HTTP mocks for fleet get package policy and Agent status + mock for all Policy Details APIs * Tests: Policy Details Trusted Apps List * Moved `seededUUIDv4()` to `BaseDataGenerator` and changed trusted apps generator to use it * change `createStartServicesMock` to optionally accept `coreStart` as input * Show api load errors on policy TA list --- .../data_generators/base_data_generator.ts | 5 + .../data_generators/trusted_app_generator.ts | 2 +- .../common/endpoint/generate_data.ts | 16 +- .../use_endpoint_privileges.test.ts | 2 +- .../common/lib/kibana/kibana_react.mock.ts | 5 +- .../mock/endpoint/app_context_render.tsx | 7 +- .../actions_context_menu.tsx | 4 +- .../artifact_card_grid.test.tsx | 152 ++++++----- .../components/grid_header.tsx | 2 +- .../artifact_entry_card.test.tsx | 10 +- .../artifact_entry_card_minified.test.tsx | 6 +- .../artifact_entry_collapsible_card.test.tsx | 104 +++++++ .../components/card_compressed_header.tsx | 68 ++--- .../artifact_entry_card/test_utils.ts | 24 +- .../context_menu_item_nav_by_router.tsx | 3 + .../context_menu_with_router_support.test.tsx | 133 +++++++++ .../context_menu_with_router_support.tsx | 13 +- .../context_menu_with_router_support/index.ts | 1 + .../management/pages/endpoint_hosts/index.tsx | 2 + .../management/pages/endpoint_hosts/mocks.ts | 120 ++------- .../management/pages/mocks/fleet_mocks.ts | 164 ++++++++++++ .../public/management/pages/mocks/index.ts | 8 + .../selectors/trusted_apps_selectors.test.ts | 185 ++++++++++++- .../selectors/trusted_apps_selectors.ts | 9 + .../pages/policy/test_utils/index.ts | 23 +- .../pages/policy/test_utils/mocks.ts | 123 +++++++++ .../list/policy_trusted_apps_list.test.tsx | 253 ++++++++++++++++++ .../list/policy_trusted_apps_list.tsx | 34 ++- 28 files changed, 1212 insertions(+), 266 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_collapsible_card.test.tsx create mode 100644 x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_with_router_support.test.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/mocks/fleet_mocks.ts create mode 100644 x-pack/plugins/security_solution/public/management/pages/mocks/index.ts create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/test_utils/mocks.ts create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.test.tsx diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index da3f387016b9f..6fbe54578f469 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -127,6 +127,11 @@ export class BaseDataGenerator { return uuid.v4(); } + /** generate a seeded random UUID v4 */ + protected seededUUIDv4(): string { + return uuid.v4({ random: [...this.randomNGenerator(255, 16)] }); + } + /** Generate a random number up to the max provided */ protected randomN(max: number): number { return Math.floor(this.random() * max); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/trusted_app_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/trusted_app_generator.ts index be0178b83be90..91c2e17a1e12d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/trusted_app_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/trusted_app_generator.ts @@ -45,7 +45,7 @@ export class TrustedAppGenerator extends BaseDataGenerator { return merge( this.generateTrustedAppForCreate(), { - id: this.randomUUID(), + id: this.seededUUIDv4(), version: this.randomString(5), created_at: this.randomPastDate(), updated_at: new Date().toISOString(), diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts index 1492e0e8c82c9..3e94dfaebc7fe 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -5,7 +5,6 @@ * 2.0. */ -import uuid from 'uuid'; import seedrandom from 'seedrandom'; import semverLte from 'semver/functions/lte'; import { assertNever } from '@kbn/std'; @@ -32,9 +31,10 @@ import { import { GetAgentPoliciesResponseItem, GetPackagesResponse, -} from '../../../fleet/common/types/rest_spec'; -import { EsAssetReference, KibanaAssetReference } from '../../../fleet/common/types/models'; -import { agentPolicyStatuses } from '../../../fleet/common/constants'; + EsAssetReference, + KibanaAssetReference, + agentPolicyStatuses, +} from '../../../fleet/common'; import { firstNonNullValue } from './models/ecs_safety_helpers'; import { EventOptions } from './types/generator'; import { BaseDataGenerator } from './data_generators/base_data_generator'; @@ -406,6 +406,7 @@ const alertsDefaultDataStream = { export class EndpointDocGenerator extends BaseDataGenerator { commonInfo: HostInfo; sequence: number = 0; + /** * The EndpointDocGenerator parameters * @@ -523,6 +524,7 @@ export class EndpointDocGenerator extends BaseDataGenerator { data_stream: metadataDataStream, }; } + /** * Creates a malware alert from the simulated host represented by this EndpointDocGenerator * @param ts - Timestamp to put in the event @@ -744,6 +746,7 @@ export class EndpointDocGenerator extends BaseDataGenerator { } return newAlert; } + /** * Creates an alert from the simulated host represented by this EndpointDocGenerator * @param ts - Timestamp to put in the event @@ -900,6 +903,7 @@ export class EndpointDocGenerator extends BaseDataGenerator { }; return newAlert; } + /** * Returns the default DLLs used in alerts */ @@ -1871,10 +1875,6 @@ export class EndpointDocGenerator extends BaseDataGenerator { }; } - private seededUUIDv4(): string { - return uuid.v4({ random: [...this.randomNGenerator(255, 16)] }); - } - private randomHostPolicyResponseActionNames(): string[] { return this.randomArray(this.randomN(8), () => this.randomChoice([ diff --git a/x-pack/plugins/security_solution/public/common/components/user_privileges/use_endpoint_privileges.test.ts b/x-pack/plugins/security_solution/public/common/components/user_privileges/use_endpoint_privileges.test.ts index 8e9dae9f12ad5..a05d1ac8d3588 100644 --- a/x-pack/plugins/security_solution/public/common/components/user_privileges/use_endpoint_privileges.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/user_privileges/use_endpoint_privileges.test.ts @@ -8,10 +8,10 @@ import { renderHook, RenderHookResult, RenderResult } from '@testing-library/react-hooks'; import { useHttp, useCurrentUser } from '../../lib/kibana'; import { EndpointPrivileges, useEndpointPrivileges } from './use_endpoint_privileges'; -import { fleetGetCheckPermissionsHttpMock } from '../../../management/pages/endpoint_hosts/mocks'; import { securityMock } from '../../../../../security/public/mocks'; import { appRoutesService } from '../../../../../fleet/common'; import { AuthenticatedUser } from '../../../../../security/common'; +import { fleetGetCheckPermissionsHttpMock } from '../../../management/pages/mocks'; jest.mock('../../lib/kibana'); diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts index df821c7ac5f6d..b98618ac76412 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts @@ -91,8 +91,9 @@ export const createUseUiSetting$Mock = () => { ]; }; -export const createStartServicesMock = (): StartServices => { - const core = coreMock.createStart(); +export const createStartServicesMock = ( + core: ReturnType = coreMock.createStart() +): StartServices => { core.uiSettings.get.mockImplementation(createUseUiSettingMock()); const { storage } = createSecuritySolutionStorageMock(); const data = dataPluginMock.createStartContract(); diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index f8a77d97b8700..20d411a0437c2 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -24,8 +24,8 @@ import { ExperimentalFeatures } from '../../../../common/experimental_features'; import { PLUGIN_ID } from '../../../../../fleet/common'; import { APP_ID, APP_PATH } from '../../../../common/constants'; import { KibanaContextProvider, KibanaServices } from '../../lib/kibana'; -import { fleetGetPackageListHttpMock } from '../../../management/pages/endpoint_hosts/mocks'; import { getDeepLinks } from '../../../app/deep_links'; +import { fleetGetPackageListHttpMock } from '../../../management/pages/mocks'; type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult; @@ -98,10 +98,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { const depsStart = depsStartMock(); const middlewareSpy = createSpyMiddleware(); const { storage } = createSecuritySolutionStorageMock(); - const startServices: StartServices = { - ...createStartServicesMock(), - ...coreStart, - }; + const startServices: StartServices = createStartServicesMock(coreStart); const storeReducer = { ...SUB_PLUGINS_REDUCER, diff --git a/x-pack/plugins/security_solution/public/management/components/actions_context_menu/actions_context_menu.tsx b/x-pack/plugins/security_solution/public/management/components/actions_context_menu/actions_context_menu.tsx index c2f9e32f61afb..c2511a31a73ae 100644 --- a/x-pack/plugins/security_solution/public/management/components/actions_context_menu/actions_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/management/components/actions_context_menu/actions_context_menu.tsx @@ -15,10 +15,11 @@ import { EuiIconProps, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import uuid from 'uuid'; import { ContextMenuItemNavByRouter, ContextMenuItemNavByRouterProps, -} from '../context_menu_with_router_support/context_menu_item_nav_by_router'; +} from '../context_menu_with_router_support'; import { useTestIdGenerator } from '../hooks/use_test_id_generator'; export interface ActionsContextMenuProps { @@ -48,6 +49,7 @@ export const ActionsContextMenu = memo( return ( { handleCloseMenu(); if (itemProps.onClick) { diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/artifact_card_grid.test.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/artifact_card_grid.test.tsx index a44076c8ad112..d360ca8fa168f 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/artifact_card_grid.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/artifact_card_grid.test.tsx @@ -5,58 +5,20 @@ * 2.0. */ -import { TrustedAppGenerator } from '../../../../common/endpoint/data_generators/trusted_app_generator'; -import { cloneDeep } from 'lodash'; -import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../common/mock/endpoint'; import React from 'react'; import { ArtifactCardGrid, ArtifactCardGridProps } from './artifact_card_grid'; - -// FIXME:PT refactor helpers below after merge of PR https://github.com/elastic/kibana/pull/113363 - -const getCommonItemDataOverrides = () => { - return { - name: 'some internal app', - description: 'this app is trusted by the company', - created_at: new Date('2021-07-01').toISOString(), - }; -}; - -const getTrustedAppProvider = () => - new TrustedAppGenerator('seed').generate(getCommonItemDataOverrides()); - -const getExceptionProvider = () => { - // cloneDeep needed because exception mock generator uses state across instances - return cloneDeep( - getExceptionListItemSchemaMock({ - ...getCommonItemDataOverrides(), - os_types: ['windows'], - updated_at: new Date().toISOString(), - created_by: 'Justa', - updated_by: 'Mara', - entries: [ - { - field: 'process.hash.*', - operator: 'included', - type: 'match', - value: '1234234659af249ddf3e40864e9fb241', - }, - { - field: 'process.executable.caseless', - operator: 'included', - type: 'match', - value: '/one/two/three', - }, - ], - tags: ['policy:all'], - }) - ); -}; +import { fireEvent, act } from '@testing-library/react'; +import { + getExceptionProviderMock, + getTrustedAppProviderMock, +} from '../artifact_entry_card/test_utils'; +import { AnyArtifact } from '../artifact_entry_card'; describe.each([ - ['trusted apps', getTrustedAppProvider], - ['exceptions/event filters', getExceptionProvider], -])('when using the ArtifactCardGrid component %s', (_, generateItem) => { + ['trusted apps', getTrustedAppProviderMock], + ['exceptions/event filters', getExceptionProviderMock], +])('when using the ArtifactCardGrid component with %s', (_, generateItem) => { let appTestContext: AppContextTestRender; let renderResult: ReturnType; let render: ( @@ -64,34 +26,45 @@ describe.each([ ) => ReturnType; let items: ArtifactCardGridProps['items']; let pageChangeHandler: jest.Mock; - let expandCollapseHandler: jest.Mock; - let cardComponentPropsProvider: Required['cardComponentProps']; + let expandCollapseHandler: jest.MockedFunction; + let cardComponentPropsProvider: jest.MockedFunction< + Required['cardComponentProps'] + >; beforeEach(() => { items = Array.from({ length: 5 }, () => generateItem()); pageChangeHandler = jest.fn(); expandCollapseHandler = jest.fn(); - cardComponentPropsProvider = jest.fn().mockReturnValue({}); + cardComponentPropsProvider = jest.fn((item) => { + return { + 'data-test-subj': `card-${items.indexOf(item as AnyArtifact)}`, + }; + }); appTestContext = createAppRootMockRenderer(); render = (props = {}) => { - renderResult = appTestContext.render( - - ); + const gridProps: ArtifactCardGridProps = { + items, + onPageChange: pageChangeHandler!, + onExpandCollapse: expandCollapseHandler!, + cardComponentProps: cardComponentPropsProvider, + pagination: { + pageSizeOptions: [5, 10], + pageSize: 5, + totalItemCount: items.length, + pageIndex: 0, + }, + 'data-test-subj': 'testGrid', + ...props, + }; + + renderResult = appTestContext.render(); return renderResult; }; }); it('should render the cards', () => { + cardComponentPropsProvider.mockImplementation(() => ({})); render(); expect(renderResult.getAllByTestId('testGrid-card')).toHaveLength(5); @@ -100,24 +73,59 @@ describe.each([ it.each([ ['header', 'testGrid-header'], ['expand/collapse placeholder', 'testGrid-header-expandCollapsePlaceHolder'], - ['name column', 'testGrid-header-layout-title'], - ['description column', 'testGrid-header-layout-description'], + ['name column', 'testGrid-header-layout-titleHolder'], + ['description column', 'testGrid-header-layout-descriptionHolder'], ['description column', 'testGrid-header-layout-cardActionsPlaceholder'], - ])('should display the Grid Header - %s', (__, selector) => { + ])('should display the Grid Header - %s', (__, testSubjId) => { render(); - expect(renderResult.getByTestId(selector)).not.toBeNull(); + expect(renderResult.getByTestId(testSubjId)).not.toBeNull(); }); - it.todo('should call onPageChange callback when paginating'); + it('should call onPageChange callback when paginating', () => { + items = Array.from({ length: 15 }, () => generateItem()); + render(); + act(() => { + fireEvent.click(renderResult.getByTestId('pagination-button-next')); + }); - it.todo('should use the props provided by cardComponentProps callback'); + expect(pageChangeHandler).toHaveBeenCalledWith({ pageIndex: 1, pageSize: 5 }); + }); - describe('and when cards are expanded/collapsed', () => { - it.todo('should call onExpandCollapse callback'); + it('should pass along the props provided by cardComponentProps callback', () => { + cardComponentPropsProvider.mockReturnValue({ 'data-test-subj': 'test-card' }); + render(); - it.todo('should provide list of cards that are expanded and collapsed'); + expect(renderResult.getAllByTestId('test-card')).toHaveLength(5); + }); - it.todo('should show card expanded if card props defined it as such'); + describe('and when cards are expanded/collapsed', () => { + it('should call onExpandCollapse callback', () => { + render(); + act(() => { + fireEvent.click(renderResult.getByTestId('card-0-header-expandCollapse')); + }); + + expect(expandCollapseHandler).toHaveBeenCalledWith({ + expanded: [items[0]], + collapsed: items.slice(1), + }); + }); + + it('should show card expanded if card props defined it as such', () => { + const originalPropsProvider = cardComponentPropsProvider.getMockImplementation(); + cardComponentPropsProvider.mockImplementation((item) => { + const props = originalPropsProvider!(item); + + if (items.indexOf(item as AnyArtifact) === 1) { + props.expanded = true; + } + + return props; + }); + render(); + + expect(renderResult.getByTestId('card-1-criteriaConditions')).not.toBeNull(); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/components/grid_header.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/components/grid_header.tsx index 03fde724b89a5..fb198e86fc386 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/components/grid_header.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_card_grid/components/grid_header.tsx @@ -63,7 +63,7 @@ export const GridHeader = memo(({ 'data-test-subj': dataTestSub } - actionMenu={false} + actionMenu={true} /> ); diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card.test.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card.test.tsx index 52f0eb5fc8982..52299679ec87b 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card.test.tsx @@ -11,11 +11,11 @@ import { ArtifactEntryCard, ArtifactEntryCardProps } from './artifact_entry_card import { act, fireEvent, getByTestId } from '@testing-library/react'; import { AnyArtifact } from './types'; import { isTrustedApp } from './utils'; -import { getTrustedAppProvider, getExceptionProvider } from './test_utils'; +import { getTrustedAppProviderMock, getExceptionProviderMock } from './test_utils'; describe.each([ - ['trusted apps', getTrustedAppProvider], - ['exceptions/event filters', getExceptionProvider], + ['trusted apps', getTrustedAppProviderMock], + ['exceptions/event filters', getExceptionProviderMock], ])('when using the ArtifactEntryCard component with %s', (_, generateItem) => { let item: AnyArtifact; let appTestContext: AppContextTestRender; @@ -48,10 +48,10 @@ describe.each([ 'some internal app' ); expect(renderResult.getByTestId('testCard-subHeader-touchedBy-createdBy').textContent).toEqual( - 'Created byJJusta' + 'Created byMMarty' ); expect(renderResult.getByTestId('testCard-subHeader-touchedBy-updatedBy').textContent).toEqual( - 'Updated byMMara' + 'Updated byEEllamae' ); }); diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card_minified.test.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card_minified.test.tsx index 1178e4b07e5bd..508dc3103ca12 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card_minified.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_card_minified.test.tsx @@ -13,11 +13,11 @@ import { } from './artifact_entry_card_minified'; import { act, fireEvent } from '@testing-library/react'; import { AnyArtifact } from './types'; -import { getTrustedAppProvider, getExceptionProvider } from './test_utils'; +import { getTrustedAppProviderMock, getExceptionProviderMock } from './test_utils'; describe.each([ - ['trusted apps', getTrustedAppProvider], - ['exceptions/event filters', getExceptionProvider], + ['trusted apps', getTrustedAppProviderMock], + ['exceptions/event filters', getExceptionProviderMock], ])('when using the ArtifactEntryCardMinified component with %s', (_, generateItem) => { let item: AnyArtifact; let appTestContext: AppContextTestRender; diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_collapsible_card.test.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_collapsible_card.test.tsx new file mode 100644 index 0000000000000..84860b1144f08 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/artifact_entry_collapsible_card.test.tsx @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../../common/mock/endpoint'; +import { act, fireEvent } from '@testing-library/react'; +import { AnyArtifact } from './types'; +import { getTrustedAppProviderMock, getExceptionProviderMock } from './test_utils'; +import { + ArtifactEntryCollapsibleCard, + ArtifactEntryCollapsibleCardProps, +} from './artifact_entry_collapsible_card'; + +describe.each([ + ['trusted apps', getTrustedAppProviderMock], + ['exceptions/event filters', getExceptionProviderMock], +])('when using the ArtifactEntryCard component with %s', (_, generateItem) => { + let item: AnyArtifact; + let appTestContext: AppContextTestRender; + let renderResult: ReturnType; + let render: ( + props?: Partial + ) => ReturnType; + let handleOnExpandCollapse: jest.MockedFunction< + ArtifactEntryCollapsibleCardProps['onExpandCollapse'] + >; + + beforeEach(() => { + item = generateItem(); + appTestContext = createAppRootMockRenderer(); + handleOnExpandCollapse = jest.fn(); + render = (props = {}) => { + const cardProps: ArtifactEntryCollapsibleCardProps = { + item, + onExpandCollapse: handleOnExpandCollapse, + 'data-test-subj': 'testCard', + ...props, + }; + + renderResult = appTestContext.render(); + return renderResult; + }; + }); + + it.each([ + ['expandCollapse button', 'testCard-header-expandCollapse'], + ['name', 'testCard-header-titleHolder'], + ['description', 'testCard-header-descriptionHolder'], + ['assignment', 'testCard-header-effectScope'], + ])('should show %s', (__, testSubjId) => { + render(); + + expect(renderResult.getByTestId(testSubjId)).not.toBeNull(); + }); + + it('should NOT show actions menu if none are defined', async () => { + render(); + + expect(renderResult.queryByTestId('testCard-header-actions')).toBeNull(); + }); + + it('should render card collapsed', () => { + render(); + + expect(renderResult.queryByTestId('testCard-header-criteriaConditions')).toBeNull(); + }); + + it('should render card expanded', () => { + render({ expanded: true }); + + expect(renderResult.getByTestId('testCard-criteriaConditions')).not.toBeNull(); + }); + + it('should call `onExpandCollapse` callback when button is clicked', () => { + render(); + act(() => { + fireEvent.click(renderResult.getByTestId('testCard-header-expandCollapse')); + }); + + expect(handleOnExpandCollapse).toHaveBeenCalled(); + }); + + it.each([ + ['title', 'testCard-header-titleHolder'], + ['description', 'testCard-header-descriptionHolder'], + ])('should truncate %s text when collapsed', (__, testSubjId) => { + render(); + + expect(renderResult.getByTestId(testSubjId).classList.contains('eui-textTruncate')).toBe(true); + }); + + it.each([ + ['title', 'testCard-header-titleHolder'], + ['description', 'testCard-header-descriptionHolder'], + ])('should NOT truncate %s text when expanded', (__, testSubjId) => { + render({ expanded: true }); + + expect(renderResult.getByTestId(testSubjId).classList.contains('eui-textTruncate')).toBe(false); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/card_compressed_header.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/card_compressed_header.tsx index 6141437779d7d..a4928ffe40674 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/card_compressed_header.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/card_compressed_header.tsx @@ -38,7 +38,6 @@ export const CardCompressedHeader = memo( 'data-test-subj': dataTestSubj, }) => { const getTestId = useTestIdGenerator(dataTestSubj); - const cssClassNames = useCollapsedCssClassNames(expanded); const policyNavLinks = usePolicyNavLinks(artifact, policies); const handleExpandCollapseClick = useCallback(() => { @@ -46,37 +45,31 @@ export const CardCompressedHeader = memo( }, [onExpandCollapse]); return ( - - + - - - - - - {artifact.name} - - - - - {artifact.description || getEmptyValue()} - - - - - - - - - + } + name={ + + {artifact.name} + + } + description={ + + {artifact.description || getEmptyValue()} + + } + effectScope={ + + } + actionMenu={} + /> ); } ); @@ -106,8 +99,11 @@ export interface CardCompressedHeaderLayoutProps extends Pick( data-test-subj={dataTestSubj} className={flushTopCssClassname} > - + {expandToggle} @@ -145,27 +145,27 @@ export const CardCompressedHeaderLayout = memo( {name} {description} {effectScope} - {actionMenu === false ? ( + {actionMenu === true ? ( { +const getCommonItemDataOverrides = () => { return { name: 'some internal app', description: 'this app is trusted by the company', @@ -17,18 +19,26 @@ export const getCommonItemDataOverrides = () => { }; }; -export const getTrustedAppProvider = () => +export const getTrustedAppProviderMock = (): TrustedApp => new TrustedAppGenerator('seed').generate(getCommonItemDataOverrides()); -export const getExceptionProvider = () => { +export const getExceptionProviderMock = (): ExceptionListItemSchema => { + // Grab the properties from the generated Trusted App that should be the same across both types + // eslint-disable-next-line @typescript-eslint/naming-convention + const { name, description, created_at, updated_at, updated_by, created_by, id } = + getTrustedAppProviderMock(); + // cloneDeep needed because exception mock generator uses state across instances return cloneDeep( getExceptionListItemSchemaMock({ - ...getCommonItemDataOverrides(), + name, + description, + created_at, + updated_at, + updated_by, + created_by, + id, os_types: ['windows'], - updated_at: new Date().toISOString(), - created_by: 'Justa', - updated_by: 'Mara', entries: [ { field: 'process.hash.*', diff --git a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_item_nav_by_router.tsx b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_item_nav_by_router.tsx index fd087f267a9b5..b955d9fe71db7 100644 --- a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_item_nav_by_router.tsx +++ b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_item_nav_by_router.tsx @@ -9,6 +9,7 @@ import React, { memo } from 'react'; import { EuiContextMenuItem, EuiContextMenuItemProps } from '@elastic/eui'; import { NavigateToAppOptions } from 'kibana/public'; import { useNavigateToAppEventHandler } from '../../../common/hooks/endpoint/use_navigate_to_app_event_handler'; +import { useTestIdGenerator } from '../hooks/use_test_id_generator'; export interface ContextMenuItemNavByRouterProps extends EuiContextMenuItemProps { /** The Kibana (plugin) app id */ @@ -34,6 +35,7 @@ export const ContextMenuItemNavByRouter = memo( ...navigateOptions, onClick, }); + const getTestId = useTestIdGenerator(otherMenuItemProps['data-test-subj']); return ( ( {textTruncate ? (
{ + let appTestContext: AppContextTestRender; + let renderResult: ReturnType; + let render: ( + props?: Partial + ) => ReturnType; + let items: ContextMenuWithRouterSupportProps['items']; + + const clickMenuTriggerButton = () => { + act(() => { + fireEvent.click(renderResult.getByTestId('testMenu-triggerButton')); + }); + }; + + const getContextMenuPanel = () => renderResult.queryByTestId('testMenu-popoverPanel'); + + beforeEach(() => { + appTestContext = createAppRootMockRenderer(); + + items = [ + { + children: 'click me 1', + 'data-test-subj': 'menu-item-one', + textTruncate: false, + }, + { + children: 'click me 2', + navigateAppId: APP_ID, + navigateOptions: { + path: '/one/two/three', + }, + href: 'http://some-url.elastic/one/two/three', + }, + { + children: 'click me 3 with some very long text here that needs to be truncated', + textTruncate: true, + }, + ]; + + render = (overrideProps = {}) => { + const props: ContextMenuWithRouterSupportProps = { + items, + 'data-test-subj': 'testMenu', + button: {'Menu'}, + ...overrideProps, + }; + + renderResult = appTestContext.render(); + + return renderResult; + }; + }); + + it('should toggle the context menu when button is clicked', () => { + render(); + + expect(getContextMenuPanel()).toBeNull(); + + clickMenuTriggerButton(); + + expect(getContextMenuPanel()).not.toBeNull(); + }); + + it('should auto include test subjects on items if one is not defined by the menu item props', () => { + render(); + clickMenuTriggerButton(); + + // this test id should be unchanged from what the Props for the item + expect(renderResult.getByTestId('menu-item-one')).not.toBeNull(); + + // these should have been auto-inserted + expect(renderResult.getByTestId('testMenu-item-1')).not.toBeNull(); + expect(renderResult.getByTestId('testMenu-item-2')).not.toBeNull(); + }); + + it('should truncate text of menu item when `textTruncate` prop is `true`', () => { + render({ maxWidth: undefined }); + clickMenuTriggerButton(); + + expect(renderResult.getByTestId('testMenu-item-2-truncateWrapper')).not.toBeNull(); + }); + + it('should close menu when a menu item is clicked and call menu item onclick callback', async () => { + render(); + clickMenuTriggerButton(); + await act(async () => { + const menuPanelRemoval = waitForElementToBeRemoved(getContextMenuPanel()); + fireEvent.click(renderResult.getByTestId('menu-item-one')); + await menuPanelRemoval; + }); + + expect(getContextMenuPanel()).toBeNull(); + }); + + it('should truncate menu and menu item content when `maxWidth` is used', () => { + render(); + clickMenuTriggerButton(); + + expect(renderResult.getByTestId('menu-item-one-truncateWrapper')).not.toBeNull(); + expect(renderResult.getByTestId('testMenu-item-1-truncateWrapper')).not.toBeNull(); + expect(renderResult.getByTestId('testMenu-item-2-truncateWrapper')).not.toBeNull(); + }); + + it('should navigate using the router when item is clicked', () => { + render(); + clickMenuTriggerButton(); + act(() => { + fireEvent.click(renderResult.getByTestId('testMenu-item-1')); + }); + + expect(appTestContext.coreStart.application.navigateToApp).toHaveBeenCalledWith( + APP_ID, + expect.objectContaining({ path: '/one/two/three' }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_with_router_support.tsx b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_with_router_support.tsx index 3f21f3995ac5b..41abb0309a7d1 100644 --- a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_with_router_support.tsx +++ b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/context_menu_with_router_support.tsx @@ -13,6 +13,7 @@ import { EuiPopover, EuiPopoverProps, } from '@elastic/eui'; +import uuid from 'uuid'; import { ContextMenuItemNavByRouter, ContextMenuItemNavByRouterProps, @@ -49,10 +50,12 @@ export const ContextMenuWithRouterSupport = memo { - return items.map((itemProps) => { + return items.map((itemProps, index) => { return ( { handleCloseMenu(); @@ -63,7 +66,7 @@ export const ContextMenuWithRouterSupport = memo ); }); - }, [handleCloseMenu, items, maxWidth]); + }, [getTestId, handleCloseMenu, items, maxWidth]); type AdditionalPanelProps = Partial>; const additionalContextMenuPanelProps = useMemo(() => { @@ -86,7 +89,11 @@ export const ContextMenuWithRouterSupport = memo +
{button}
} diff --git a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/index.ts b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/index.ts index 56c6009ccf1b2..527183ef40697 100644 --- a/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/index.ts +++ b/x-pack/plugins/security_solution/public/management/components/context_menu_with_router_support/index.ts @@ -6,3 +6,4 @@ */ export * from './context_menu_with_router_support'; +export * from './context_menu_item_nav_by_router'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx index 30397fe1d32f2..70f5bca339c82 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx @@ -24,3 +24,5 @@ export const EndpointsContainer = memo(() => { }); EndpointsContainer.displayName = 'EndpointsContainer'; +export { endpointListFleetApisHttpMock } from './mocks'; +export { EndpointListFleetApisHttpMockInterface } from './mocks'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts index 010fe48f29418..e0b5837c2f78a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts @@ -26,19 +26,21 @@ import { HOST_METADATA_LIST_ROUTE, } from '../../../../common/endpoint/constants'; import { - AGENT_POLICY_API_ROUTES, - appRoutesService, - CheckPermissionsResponse, - EPM_API_ROUTES, - GetAgentPoliciesResponse, - GetPackagesResponse, -} from '../../../../../fleet/common'; -import { - PendingActionsHttpMockInterface, pendingActionsHttpMock, + PendingActionsHttpMockInterface, } from '../../../common/lib/endpoint_pending_actions/mocks'; import { METADATA_TRANSFORM_STATS_URL, TRANSFORM_STATES } from '../../../../common/constants'; import { TransformStatsResponse } from './types'; +import { + fleetGetAgentPolicyListHttpMock, + FleetGetAgentPolicyListHttpMockInterface, + FleetGetAgentStatusHttpMockInterface, + fleetGetCheckPermissionsHttpMock, + FleetGetCheckPermissionsInterface, + FleetGetEndpointPackagePolicyHttpMockInterface, + fleetGetPackageListHttpMock, + FleetGetPackageListHttpMockInterface, +} from '../mocks'; type EndpointMetadataHttpMocksInterface = ResponseProvidersInterface<{ metadataList: () => HostResultList; @@ -149,88 +151,6 @@ export const endpointActivityLogHttpMock = }, ]); -export type FleetGetPackageListHttpMockInterface = ResponseProvidersInterface<{ - packageList: () => GetPackagesResponse; -}>; -export const fleetGetPackageListHttpMock = - httpHandlerMockFactory([ - { - id: 'packageList', - method: 'get', - path: EPM_API_ROUTES.LIST_PATTERN, - handler() { - const generator = new EndpointDocGenerator('seed'); - - return { - response: [generator.generateEpmPackage()], - }; - }, - }, - ]); - -export type FleetGetAgentPolicyListHttpMockInterface = ResponseProvidersInterface<{ - agentPolicy: () => GetAgentPoliciesResponse; -}>; -export const fleetGetAgentPolicyListHttpMock = - httpHandlerMockFactory([ - { - id: 'agentPolicy', - path: AGENT_POLICY_API_ROUTES.LIST_PATTERN, - method: 'get', - handler: () => { - const generator = new EndpointDocGenerator('seed'); - const endpointMetadata = generator.generateHostMetadata(); - const agentPolicy = generator.generateAgentPolicy(); - - // Make sure that the Agent policy returned from the API has the Integration Policy ID that - // the endpoint metadata is using. This is needed especially when testing the Endpoint Details - // flyout where certain actions might be disabled if we know the endpoint integration policy no - // longer exists. - (agentPolicy.package_policies as string[]).push( - endpointMetadata.Endpoint.policy.applied.id - ); - - return { - items: [agentPolicy], - perPage: 10, - total: 1, - page: 1, - }; - }, - }, - ]); - -export type FleetGetCheckPermissionsInterface = ResponseProvidersInterface<{ - checkPermissions: () => CheckPermissionsResponse; -}>; - -export const fleetGetCheckPermissionsHttpMock = - httpHandlerMockFactory([ - { - id: 'checkPermissions', - path: appRoutesService.getCheckPermissionsPath(), - method: 'get', - handler: () => { - return { - error: undefined, - success: true, - }; - }, - }, - ]); - -type FleetApisHttpMockInterface = FleetGetPackageListHttpMockInterface & - FleetGetAgentPolicyListHttpMockInterface & - FleetGetCheckPermissionsInterface; -/** - * Mocks all Fleet apis needed to render the Endpoint List/Details pages - */ -export const fleetApisHttpMock = composeHttpHandlerMocks([ - fleetGetPackageListHttpMock, - fleetGetAgentPolicyListHttpMock, - fleetGetCheckPermissionsHttpMock, -]); - type TransformHttpMocksInterface = ResponseProvidersInterface<{ metadataTransformStats: () => TransformStatsResponse; }>; @@ -251,10 +171,24 @@ export const transformsHttpMocks = httpHandlerMockFactory([ + fleetGetPackageListHttpMock, + fleetGetAgentPolicyListHttpMock, + fleetGetCheckPermissionsHttpMock, + ]); type EndpointPageHttpMockInterface = EndpointMetadataHttpMocksInterface & EndpointPolicyResponseHttpMockInterface & EndpointActivityLogHttpMockInterface & - FleetApisHttpMockInterface & + EndpointListFleetApisHttpMockInterface & PendingActionsHttpMockInterface & TransformHttpMocksInterface; /** @@ -264,7 +198,7 @@ export const endpointPageHttpMock = composeHttpHandlerMocks GetPackagesResponse; +}>; +export const fleetGetPackageListHttpMock = + httpHandlerMockFactory([ + { + id: 'packageList', + method: 'get', + path: EPM_API_ROUTES.LIST_PATTERN, + handler() { + const generator = new EndpointDocGenerator('seed'); + + return { + response: [generator.generateEpmPackage()], + }; + }, + }, + ]); + +export type FleetGetEndpointPackagePolicyHttpMockInterface = ResponseProvidersInterface<{ + endpointPackagePolicy: () => GetPolicyResponse; +}>; +export const fleetGetEndpointPackagePolicyHttpMock = + httpHandlerMockFactory([ + { + id: 'endpointPackagePolicy', + path: PACKAGE_POLICY_API_ROUTES.INFO_PATTERN, + method: 'get', + handler: () => { + return { + items: new EndpointDocGenerator('seed').generatePolicyPackagePolicy(), + }; + }, + }, + ]); + +export type FleetGetEndpointPackagePolicyListHttpMockInterface = ResponseProvidersInterface<{ + endpointPackagePolicyList: () => GetPolicyListResponse; +}>; +export const fleetGetEndpointPackagePolicyListHttpMock = + httpHandlerMockFactory([ + { + id: 'endpointPackagePolicyList', + path: PACKAGE_POLICY_API_ROUTES.LIST_PATTERN, + method: 'get', + handler: () => { + const generator = new EndpointDocGenerator('seed'); + + const items = Array.from({ length: 5 }, (_, index) => { + const policy = generator.generatePolicyPackagePolicy(); + policy.name += ` ${index}`; + return policy; + }); + + return { + items, + total: 1, + page: 1, + perPage: 10, + }; + }, + }, + ]); + +export type FleetGetAgentPolicyListHttpMockInterface = ResponseProvidersInterface<{ + agentPolicy: () => GetAgentPoliciesResponse; +}>; +export const fleetGetAgentPolicyListHttpMock = + httpHandlerMockFactory([ + { + id: 'agentPolicy', + path: AGENT_POLICY_API_ROUTES.LIST_PATTERN, + method: 'get', + handler: () => { + const generator = new EndpointDocGenerator('seed'); + const endpointMetadata = generator.generateHostMetadata(); + const agentPolicy = generator.generateAgentPolicy(); + + // Make sure that the Agent policy returned from the API has the Integration Policy ID that + // the endpoint metadata is using. This is needed especially when testing the Endpoint Details + // flyout where certain actions might be disabled if we know the endpoint integration policy no + // longer exists. + (agentPolicy.package_policies as string[]).push( + endpointMetadata.Endpoint.policy.applied.id + ); + + return { + items: [agentPolicy], + perPage: 10, + total: 1, + page: 1, + }; + }, + }, + ]); + +export type FleetGetCheckPermissionsInterface = ResponseProvidersInterface<{ + checkPermissions: () => CheckPermissionsResponse; +}>; +export const fleetGetCheckPermissionsHttpMock = + httpHandlerMockFactory([ + { + id: 'checkPermissions', + path: appRoutesService.getCheckPermissionsPath(), + method: 'get', + handler: () => { + return { + error: undefined, + success: true, + }; + }, + }, + ]); + +export type FleetGetAgentStatusHttpMockInterface = ResponseProvidersInterface<{ + agentStatus: () => GetAgentStatusResponse; +}>; +export const fleetGetAgentStatusHttpMock = + httpHandlerMockFactory([ + { + id: 'agentStatus', + path: AGENT_API_ROUTES.STATUS_PATTERN, + method: 'get', + handler: () => { + return { + results: { + total: 50, + inactive: 5, + online: 40, + error: 0, + offline: 5, + updating: 0, + other: 0, + events: 0, + }, + }; + }, + }, + ]); diff --git a/x-pack/plugins/security_solution/public/management/pages/mocks/index.ts b/x-pack/plugins/security_solution/public/management/pages/mocks/index.ts new file mode 100644 index 0000000000000..c7388cad5696f --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/mocks/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './fleet_mocks'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.test.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.test.ts index 6839edb965332..0fbd674b265b0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PolicyDetailsState } from '../../../types'; +import { PolicyArtifactsState, PolicyDetailsState } from '../../../types'; import { initialPolicyDetailsState } from '../reducer'; import { getAssignableArtifactsList, @@ -16,6 +16,12 @@ import { getAssignableArtifactsListExist, getAssignableArtifactsListExistIsLoading, getUpdateArtifacts, + doesPolicyTrustedAppsListNeedUpdate, + isPolicyTrustedAppListLoading, + getPolicyTrustedAppList, + getPolicyTrustedAppsListPagination, + getTrustedAppsListOfAllPolicies, + getTrustedAppsAllPoliciesById, } from './trusted_apps_selectors'; import { getCurrentArtifactsLocation, isOnPolicyTrustedAppsView } from './policy_common_selectors'; @@ -27,15 +33,190 @@ import { createFailedResourceState, } from '../../../../../state'; import { MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH } from '../../../../../common/constants'; -import { getMockListResponse, getAPIError, getMockCreateResponse } from '../../../test_utils'; +import { + getMockListResponse, + getAPIError, + getMockCreateResponse, + getMockPolicyDetailsArtifactListUrlParams, + getMockPolicyDetailsArtifactsPageLocationUrlParams, +} from '../../../test_utils'; +import { getGeneratedPolicyResponse } from '../../../../trusted_apps/store/mocks'; describe('policy trusted apps selectors', () => { let initialState: ImmutableObject; + const createArtifactsState = ( + artifacts: Partial = {} + ): ImmutableObject => { + return { + ...initialState, + artifacts: { + ...initialState.artifacts, + ...artifacts, + }, + }; + }; + beforeEach(() => { initialState = initialPolicyDetailsState(); }); + describe('doesPolicyTrustedAppsListNeedUpdate()', () => { + it('should return true if state is not loaded', () => { + expect(doesPolicyTrustedAppsListNeedUpdate(initialState)).toBe(true); + }); + + it('should return true if it is loaded, but URL params were changed', () => { + expect( + doesPolicyTrustedAppsListNeedUpdate( + createArtifactsState({ + location: getMockPolicyDetailsArtifactsPageLocationUrlParams({ page_index: 4 }), + assignedList: createLoadedResourceState({ + location: getMockPolicyDetailsArtifactListUrlParams(), + artifacts: getMockListResponse(), + }), + }) + ) + ).toBe(true); + }); + + it('should return false if state is loaded adn URL params are the same', () => { + expect( + doesPolicyTrustedAppsListNeedUpdate( + createArtifactsState({ + location: getMockPolicyDetailsArtifactsPageLocationUrlParams(), + assignedList: createLoadedResourceState({ + location: getMockPolicyDetailsArtifactListUrlParams(), + artifacts: getMockListResponse(), + }), + }) + ) + ).toBe(false); + }); + }); + + describe('isPolicyTrustedAppListLoading()', () => { + it('should return true when loading data', () => { + expect( + isPolicyTrustedAppListLoading( + createArtifactsState({ + assignedList: createLoadingResourceState(createUninitialisedResourceState()), + }) + ) + ).toBe(true); + }); + + it.each([ + ['uninitialized', createUninitialisedResourceState() as PolicyArtifactsState['assignedList']], + ['loaded', createLoadedResourceState({}) as PolicyArtifactsState['assignedList']], + ['failed', createFailedResourceState({}) as PolicyArtifactsState['assignedList']], + ])('should return false when state is %s', (__, assignedListState) => { + expect( + isPolicyTrustedAppListLoading(createArtifactsState({ assignedList: assignedListState })) + ).toBe(false); + }); + }); + + describe('getPolicyTrustedAppList()', () => { + it('should return the list of trusted apps', () => { + const listResponse = getMockListResponse(); + + expect( + getPolicyTrustedAppList( + createArtifactsState({ + location: getMockPolicyDetailsArtifactsPageLocationUrlParams(), + assignedList: createLoadedResourceState({ + location: getMockPolicyDetailsArtifactListUrlParams(), + artifacts: listResponse, + }), + }) + ) + ).toEqual(listResponse.data); + }); + + it('should return empty array if no data is loaded', () => { + expect(getPolicyTrustedAppList(initialState)).toEqual([]); + }); + }); + + describe('getPolicyTrustedAppsListPagination()', () => { + it('should return default pagination data even if no api data is available', () => { + expect(getPolicyTrustedAppsListPagination(initialState)).toEqual({ + pageIndex: 0, + pageSize: 10, + pageSizeOptions: [10, 20, 50], + totalItemCount: 0, + }); + }); + + it('should return pagination data based on api response data', () => { + const listResponse = getMockListResponse(); + + listResponse.page = 6; + listResponse.per_page = 100; + listResponse.total = 1000; + + expect( + getPolicyTrustedAppsListPagination( + createArtifactsState({ + location: getMockPolicyDetailsArtifactsPageLocationUrlParams({ + page_index: 5, + page_size: 100, + }), + assignedList: createLoadedResourceState({ + location: getMockPolicyDetailsArtifactListUrlParams({ + page_index: 5, + page_size: 100, + }), + artifacts: listResponse, + }), + }) + ) + ).toEqual({ + pageIndex: 5, + pageSize: 100, + pageSizeOptions: [10, 20, 50], + totalItemCount: 1000, + }); + }); + }); + + describe('getTrustedAppsListOfAllPolicies()', () => { + it('should return the loaded list of policies', () => { + const policiesApiResponse = getGeneratedPolicyResponse(); + + expect( + getTrustedAppsListOfAllPolicies( + createArtifactsState({ + policies: createLoadedResourceState(policiesApiResponse), + }) + ) + ).toEqual(policiesApiResponse.items); + }); + + it('should return an empty array of no policy data was loaded yet', () => { + expect(getTrustedAppsListOfAllPolicies(initialState)).toEqual([]); + }); + }); + + describe('getTrustedAppsAllPoliciesById()', () => { + it('should return an empty object if no polices', () => { + expect(getTrustedAppsAllPoliciesById(initialState)).toEqual({}); + }); + + it('should return an object with policy id and policy data', () => { + const policiesApiResponse = getGeneratedPolicyResponse(); + + expect( + getTrustedAppsAllPoliciesById( + createArtifactsState({ + policies: createLoadedResourceState(policiesApiResponse), + }) + ) + ).toEqual({ [policiesApiResponse.items[0].id]: policiesApiResponse.items[0] }); + }); + }); + describe('isOnPolicyTrustedAppsPage()', () => { it('when location is on policy trusted apps page', () => { const isOnPage = isOnPolicyTrustedAppsView({ diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts index 84f0f4a2c63b8..3177f13ae77e8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts @@ -31,6 +31,7 @@ import { LoadedResourceState, } from '../../../../../state'; import { getCurrentArtifactsLocation } from './policy_common_selectors'; +import { ServerApiError } from '../../../../../../common/types'; export const doesPolicyHaveTrustedApps = ( state: PolicyDetailsState @@ -212,3 +213,11 @@ export const getDoesAnyTrustedAppExistsIsLoading: PolicyDetailsSelector return isLoadingResourceState(doesAnyTrustedAppExists); } ); + +export const getPolicyTrustedAppListError: PolicyDetailsSelector< + Immutable | undefined +> = createSelector(getCurrentPolicyAssignedTrustedAppsState, (currentAssignedTrustedAppsState) => { + if (isFailedResourceState(currentAssignedTrustedAppsState)) { + return currentAssignedTrustedAppsState.error; + } +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/index.ts index d92c41f5a1cc6..599c6328855e5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/index.ts @@ -5,25 +5,4 @@ * 2.0. */ -import { - GetTrustedAppsListResponse, - PostTrustedAppCreateResponse, -} from '../../../../../common/endpoint/types'; - -import { createSampleTrustedApps, createSampleTrustedApp } from '../../trusted_apps/test_utils'; - -export const getMockListResponse: () => GetTrustedAppsListResponse = () => ({ - data: createSampleTrustedApps({}), - per_page: 100, - page: 1, - total: 100, -}); - -export const getMockCreateResponse: () => PostTrustedAppCreateResponse = () => - createSampleTrustedApp(1) as unknown as unknown as PostTrustedAppCreateResponse; - -export const getAPIError = () => ({ - statusCode: 500, - error: 'Internal Server Error', - message: 'Something is not right', -}); +export * from './mocks'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/mocks.ts b/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/mocks.ts new file mode 100644 index 0000000000000..be38e591dd9da --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/test_utils/mocks.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + composeHttpHandlerMocks, + httpHandlerMockFactory, + ResponseProvidersInterface, +} from '../../../../common/mock/endpoint/http_handler_mock_factory'; +import { + GetTrustedAppsListRequest, + GetTrustedAppsListResponse, + PostTrustedAppCreateResponse, +} from '../../../../../common/endpoint/types'; +import { TRUSTED_APPS_LIST_API } from '../../../../../common/endpoint/constants'; +import { TrustedAppGenerator } from '../../../../../common/endpoint/data_generators/trusted_app_generator'; +import { createSampleTrustedApps, createSampleTrustedApp } from '../../trusted_apps/test_utils'; +import { + PolicyDetailsArtifactsPageListLocationParams, + PolicyDetailsArtifactsPageLocation, +} from '../types'; +import { + fleetGetAgentStatusHttpMock, + FleetGetAgentStatusHttpMockInterface, + fleetGetEndpointPackagePolicyHttpMock, + FleetGetEndpointPackagePolicyHttpMockInterface, + fleetGetEndpointPackagePolicyListHttpMock, + FleetGetEndpointPackagePolicyListHttpMockInterface, +} from '../../mocks'; + +export const getMockListResponse: () => GetTrustedAppsListResponse = () => ({ + data: createSampleTrustedApps({}), + per_page: 100, + page: 1, + total: 100, +}); + +export const getMockPolicyDetailsArtifactsPageLocationUrlParams = ( + overrides: Partial = {} +): PolicyDetailsArtifactsPageLocation => { + return { + page_index: 0, + page_size: 10, + filter: '', + show: undefined, + ...overrides, + }; +}; + +export const getMockPolicyDetailsArtifactListUrlParams = ( + overrides: Partial = {} +): PolicyDetailsArtifactsPageListLocationParams => { + return { + page_index: 0, + page_size: 10, + filter: '', + ...overrides, + }; +}; + +export const getMockCreateResponse: () => PostTrustedAppCreateResponse = () => + createSampleTrustedApp(1) as unknown as unknown as PostTrustedAppCreateResponse; + +export const getAPIError = () => ({ + statusCode: 500, + error: 'Internal Server Error', + message: 'Something is not right', +}); + +type PolicyDetailsTrustedAppsHttpMocksInterface = ResponseProvidersInterface<{ + policyTrustedAppsList: () => GetTrustedAppsListResponse; +}>; + +/** + * HTTP mocks that support the Trusted Apps tab of the Policy Details page + */ +export const policyDetailsTrustedAppsHttpMocks = + httpHandlerMockFactory([ + { + id: 'policyTrustedAppsList', + path: TRUSTED_APPS_LIST_API, + method: 'get', + handler: ({ query }): GetTrustedAppsListResponse => { + const apiQueryParams = query as GetTrustedAppsListRequest; + const generator = new TrustedAppGenerator('seed'); + const perPage = apiQueryParams.per_page ?? 10; + const data = Array.from({ length: Math.min(perPage, 50) }, () => generator.generate()); + + // Change the 3rd entry (index 2) to be policy specific + data[2].effectScope = { + type: 'policy', + policies: [ + // IDs below are those generated by the `fleetGetEndpointPackagePolicyListHttpMock()` mock + 'ddf6570b-9175-4a6d-b288-61a09771c647', + 'b8e616ae-44fc-4be7-846c-ce8fa5c082dd', + ], + }; + + return { + page: apiQueryParams.page ?? 1, + per_page: perPage, + total: 20, + data, + }; + }, + }, + ]); + +export type PolicyDetailsPageAllApiHttpMocksInterface = + FleetGetEndpointPackagePolicyHttpMockInterface & + FleetGetAgentStatusHttpMockInterface & + FleetGetEndpointPackagePolicyListHttpMockInterface & + PolicyDetailsTrustedAppsHttpMocksInterface; +export const policyDetailsPageAllApiHttpMocks = + composeHttpHandlerMocks([ + fleetGetEndpointPackagePolicyHttpMock, + fleetGetAgentStatusHttpMock, + fleetGetEndpointPackagePolicyListHttpMock, + policyDetailsTrustedAppsHttpMocks, + ]); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.test.tsx new file mode 100644 index 0000000000000..07b62d13e8edc --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.test.tsx @@ -0,0 +1,253 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + AppContextTestRender, + createAppRootMockRenderer, +} from '../../../../../../common/mock/endpoint'; +import { getPolicyDetailsArtifactsListPath } from '../../../../../common/routing'; +import { PolicyTrustedAppsList } from './policy_trusted_apps_list'; +import React from 'react'; +import { policyDetailsPageAllApiHttpMocks } from '../../../test_utils'; +import { isFailedResourceState, isLoadedResourceState } from '../../../../../state'; +import { fireEvent, within, act, waitFor } from '@testing-library/react'; +import { APP_ID } from '../../../../../../../common/constants'; + +describe('when rendering the PolicyTrustedAppsList', () => { + let appTestContext: AppContextTestRender; + let renderResult: ReturnType; + let render: (waitForLoadedState?: boolean) => Promise>; + let mockedApis: ReturnType; + let waitForAction: AppContextTestRender['middlewareSpy']['waitForAction']; + + const getCardByIndexPosition = (cardIndex: number = 0) => { + const card = renderResult.getAllByTestId('policyTrustedAppsGrid-card')[cardIndex]; + + if (!card) { + throw new Error(`Card at index [${cardIndex}] not found`); + } + + return card; + }; + + const toggleCardExpandCollapse = (cardIndex: number = 0) => { + act(() => { + fireEvent.click( + within(getCardByIndexPosition(cardIndex)).getByTestId( + 'policyTrustedAppsGrid-card-header-expandCollapse' + ) + ); + }); + }; + + const toggleCardActionMenu = async (cardIndex: number = 0) => { + act(() => { + fireEvent.click( + within(getCardByIndexPosition(cardIndex)).getByTestId( + 'policyTrustedAppsGrid-card-header-actions-button' + ) + ); + }); + + await waitFor(() => + expect(renderResult.getByTestId('policyTrustedAppsGrid-card-header-actions-contextMenuPanel')) + ); + }; + + beforeEach(() => { + appTestContext = createAppRootMockRenderer(); + + mockedApis = policyDetailsPageAllApiHttpMocks(appTestContext.coreStart.http); + appTestContext.setExperimentalFlag({ trustedAppsByPolicyEnabled: true }); + waitForAction = appTestContext.middlewareSpy.waitForAction; + + render = async (waitForLoadedState: boolean = true) => { + appTestContext.history.push( + getPolicyDetailsArtifactsListPath('ddf6570b-9175-4a6d-b288-61a09771c647') + ); + const trustedAppDataReceived = waitForLoadedState + ? waitForAction('assignedTrustedAppsListStateChanged', { + validate({ payload }) { + return isLoadedResourceState(payload); + }, + }) + : Promise.resolve(); + + renderResult = appTestContext.render(); + await trustedAppDataReceived; + + return renderResult; + }; + }); + + // FIXME: implement this test once PR #113802 is merged + it.todo('should show loading spinner if checking to see if trusted apps exist'); + + it('should show total number of of items being displayed', async () => { + await render(); + + expect(renderResult.getByTestId('policyDetailsTrustedAppsCount').textContent).toBe( + 'Showing 20 trusted applications' + ); + }); + + it('should show card grid', async () => { + await render(); + + expect(renderResult.getByTestId('policyTrustedAppsGrid')).toBeTruthy(); + await expect(renderResult.findAllByTestId('policyTrustedAppsGrid-card')).resolves.toHaveLength( + 10 + ); + }); + + it('should expand cards', async () => { + await render(); + // expand + toggleCardExpandCollapse(); + toggleCardExpandCollapse(4); + + await waitFor(() => + expect( + renderResult.queryAllByTestId('policyTrustedAppsGrid-card-criteriaConditions') + ).toHaveLength(2) + ); + }); + + it('should collapse cards', async () => { + await render(); + + // expand + toggleCardExpandCollapse(); + toggleCardExpandCollapse(4); + + await waitFor(() => + expect( + renderResult.queryAllByTestId('policyTrustedAppsGrid-card-criteriaConditions') + ).toHaveLength(2) + ); + + // collapse + toggleCardExpandCollapse(); + toggleCardExpandCollapse(4); + + await waitFor(() => + expect( + renderResult.queryAllByTestId('policyTrustedAppsGrid-card-criteriaConditions') + ).toHaveLength(0) + ); + }); + + it('should show action menu on card', async () => { + await render(); + expect( + renderResult.getAllByTestId('policyTrustedAppsGrid-card-header-actions-button') + ).toHaveLength(10); + }); + + it('should navigate to trusted apps page when view full details action is clicked', async () => { + await render(); + await toggleCardActionMenu(); + act(() => { + fireEvent.click(renderResult.getByTestId('policyTrustedAppsGrid-viewFullDetailsAction')); + }); + + expect(appTestContext.coreStart.application.navigateToApp).toHaveBeenCalledWith( + APP_ID, + expect.objectContaining({ + path: '/administration/trusted_apps?show=edit&id=89f72d8a-05b5-4350-8cad-0dc3661d6e67', + }) + ); + }); + + it('should display policy names on assignment context menu', async () => { + const retrieveAllPolicies = waitForAction('policyDetailsListOfAllPoliciesStateChanged', { + validate({ payload }) { + return isLoadedResourceState(payload); + }, + }); + await render(); + await retrieveAllPolicies; + act(() => { + fireEvent.click( + within(getCardByIndexPosition(2)).getByTestId( + 'policyTrustedAppsGrid-card-header-effectScope-popupMenu-button' + ) + ); + }); + await waitFor(() => + expect( + renderResult.getByTestId( + 'policyTrustedAppsGrid-card-header-effectScope-popupMenu-popoverPanel' + ) + ) + ); + + expect( + renderResult.getByTestId('policyTrustedAppsGrid-card-header-effectScope-popupMenu-item-0') + .textContent + ).toEqual('Endpoint Policy 0'); + expect( + renderResult.getByTestId('policyTrustedAppsGrid-card-header-effectScope-popupMenu-item-1') + .textContent + ).toEqual('Endpoint Policy 1'); + }); + + it.todo('should navigate to policy details when clicking policy on assignment context menu'); + + it('should handle pagination changes', async () => { + await render(); + + expect(appTestContext.history.location.search).not.toBeTruthy(); + + act(() => { + fireEvent.click(renderResult.getByTestId('pagination-button-next')); + }); + + expect(appTestContext.history.location.search).toMatch('?page_index=1'); + }); + + it('should reset `pageIndex` when a new pageSize is selected', async () => { + await render(); + // page ahead + act(() => { + fireEvent.click(renderResult.getByTestId('pagination-button-next')); + }); + await waitFor(() => { + expect(appTestContext.history.location.search).toBeTruthy(); + }); + + // now change the page size + await act(async () => { + fireEvent.click(renderResult.getByTestId('tablePaginationPopoverButton')); + await waitFor(() => expect(renderResult.getByTestId('tablePagination-50-rows'))); + }); + act(() => { + fireEvent.click(renderResult.getByTestId('tablePagination-50-rows')); + }); + + expect(appTestContext.history.location.search).toMatch('?page_size=50'); + }); + + it('should show toast message if trusted app list api call fails', async () => { + const error = new Error('oh no'); + // @ts-expect-error + mockedApis.responseProvider.policyTrustedAppsList.mockRejectedValue(error); + await render(false); + await act(async () => { + await waitForAction('assignedTrustedAppsListStateChanged', { + validate: ({ payload }) => isFailedResourceState(payload), + }); + }); + + expect(appTestContext.startServices.notifications.toasts.addError).toHaveBeenCalledWith( + error, + expect.objectContaining({ + title: expect.any(String), + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.tsx index 333820b5d81b4..6793bee9c3c01 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/list/policy_trusted_apps_list.tsx @@ -19,6 +19,7 @@ import { doesPolicyHaveTrustedApps, getCurrentArtifactsLocation, getPolicyTrustedAppList, + getPolicyTrustedAppListError, getPolicyTrustedAppsListPagination, getTrustedAppsAllPoliciesById, isPolicyTrustedAppListLoading, @@ -31,12 +32,17 @@ import { getTrustedAppsListPath, } from '../../../../../common/routing'; import { Immutable, TrustedApp } from '../../../../../../../common/endpoint/types'; -import { useAppUrl } from '../../../../../../common/lib/kibana'; +import { useAppUrl, useToasts } from '../../../../../../common/lib/kibana'; import { APP_ID } from '../../../../../../../common/constants'; import { ContextMenuItemNavByRouterProps } from '../../../../../components/context_menu_with_router_support/context_menu_item_nav_by_router'; import { ArtifactEntryCollapsibleCardProps } from '../../../../../components/artifact_entry_card'; +import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; + +const DATA_TEST_SUBJ = 'policyTrustedAppsGrid'; export const PolicyTrustedAppsList = memo(() => { + const getTestId = useTestIdGenerator(DATA_TEST_SUBJ); + const toasts = useToasts(); const history = useHistory(); const { getAppUrl } = useAppUrl(); const policyId = usePolicyDetailsSelector(policyIdFromParams); @@ -47,11 +53,10 @@ export const PolicyTrustedAppsList = memo(() => { const pagination = usePolicyDetailsSelector(getPolicyTrustedAppsListPagination); const urlParams = usePolicyDetailsSelector(getCurrentArtifactsLocation); const allPoliciesById = usePolicyDetailsSelector(getTrustedAppsAllPoliciesById); + const trustedAppsApiError = usePolicyDetailsSelector(getPolicyTrustedAppListError); const [isCardExpanded, setCardExpanded] = useState>({}); - // TODO:PT show load errors if any - const handlePageChange = useCallback( ({ pageIndex, pageSize }) => { history.push( @@ -135,6 +140,7 @@ export const PolicyTrustedAppsList = memo(() => { href: getAppUrl({ appId: APP_ID, path: viewUrlPath }), navigateAppId: APP_ID, navigateOptions: { path: viewUrlPath }, + 'data-test-subj': getTestId('viewFullDetailsAction'), }, ], policies: assignedPoliciesMenuItems, @@ -144,7 +150,7 @@ export const PolicyTrustedAppsList = memo(() => { } return newCardProps; - }, [allPoliciesById, getAppUrl, isCardExpanded, trustedAppItems]); + }, [allPoliciesById, getAppUrl, getTestId, isCardExpanded, trustedAppItems]); const provideCardProps = useCallback['cardComponentProps']>( (item) => { @@ -153,6 +159,17 @@ export const PolicyTrustedAppsList = memo(() => { [cardProps] ); + // if an error occurred while loading the data, show toast + useEffect(() => { + if (trustedAppsApiError) { + toasts.addError(trustedAppsApiError as unknown as Error, { + title: i18n.translate('xpack.securitySolution.endpoint.policy.trustedApps.list.apiError', { + defaultMessage: 'Error while retrieving list of trusted applications', + }), + }); + } + }, [toasts, trustedAppsApiError]); + // Anytime a new set of data (trusted apps) is retrieved, reset the card expand state useEffect(() => { setCardExpanded({}); @@ -161,7 +178,11 @@ export const PolicyTrustedAppsList = memo(() => { if (hasTrustedApps.loading || isTrustedAppExistsCheckLoading) { return ( - + ); } @@ -180,8 +201,9 @@ export const PolicyTrustedAppsList = memo(() => { onExpandCollapse={handleExpandCollapse} cardComponentProps={provideCardProps} loading={isLoading} + error={trustedAppsApiError?.message} pagination={pagination as Pagination} - data-test-subj="policyTrustedAppsGrid" + data-test-subj={DATA_TEST_SUBJ} /> ); From c9e3e0e9b5c8703f8dd2b8e815cbd5ea5f0f2c4c Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Tue, 12 Oct 2021 08:26:05 -0500 Subject: [PATCH 47/73] Fix GC time calculation (#113992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was in µs. Corrected to be in ms. Also use correct duration formatting on the GC time chart and time spent by dependency chart. --- .../shared/charts/breakdown_chart/index.tsx | 12 +- .../shared/charts/metrics_chart/index.tsx | 16 +- .../gc/fetch_and_transform_gc_metrics.test.ts | 133 ++++++++ .../java/gc/fetch_and_transform_gc_metrics.ts | 9 +- .../tests/metrics_charts/metrics_charts.ts | 316 +++++++++--------- 5 files changed, 317 insertions(+), 169 deletions(-) create mode 100644 x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts diff --git a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx index 9dc2fbd4cc961..213bac40c2248 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx @@ -27,8 +27,8 @@ import { Annotation } from '../../../../../common/annotations'; import { useChartTheme } from '../../../../../../observability/public'; import { asAbsoluteDateTime, - asDuration, asPercent, + getDurationFormatter, } from '../../../../../common/utils/formatters'; import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; import { useChartPointerEventContext } from '../../../../context/chart_pointer_event/use_chart_pointer_event_context'; @@ -39,6 +39,10 @@ import { ChartContainer } from '../../charts/chart_container'; import { isTimeseriesEmpty, onBrushEnd } from '../../charts/helper/helper'; import { useApmParams } from '../../../../hooks/use_apm_params'; import { useTimeRange } from '../../../../hooks/use_time_range'; +import { + getMaxY, + getResponseTimeTickFormatter, +} from '../../../shared/charts/transaction_charts/helper'; interface Props { fetchStatus: FETCH_STATUS; @@ -50,7 +54,6 @@ interface Props { } const asPercentBound = (y: number | null) => asPercent(y, 1); -const asDurationBound = (y: number | null) => asDuration(y); export function BreakdownChart({ fetchStatus, @@ -82,8 +85,11 @@ export function BreakdownChart({ const isEmpty = isTimeseriesEmpty(timeseries); + const maxY = getMaxY(timeseries); const yTickFormat: TickFormatter = - yAxisType === 'duration' ? asDurationBound : asPercentBound; + yAxisType === 'duration' + ? getResponseTimeTickFormatter(getDurationFormatter(maxY)) + : asPercentBound; return ( diff --git a/x-pack/plugins/apm/public/components/shared/charts/metrics_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/metrics_chart/index.tsx index 9ee77cd95ee0d..9f437a95e7dd9 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/metrics_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/metrics_chart/index.tsx @@ -9,9 +9,9 @@ import { EuiTitle } from '@elastic/eui'; import React from 'react'; import { asDecimal, - asDuration, asInteger, asPercent, + getDurationFormatter, getFixedByteFormatter, } from '../../../../../common/utils/formatters'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -19,22 +19,24 @@ import { GenericMetricsChart } from '../../../../../server/lib/metrics/transform import { Maybe } from '../../../../../typings/common'; import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; import { TimeseriesChart } from '../timeseries_chart'; +import { + getMaxY, + getResponseTimeTickFormatter, +} from '../transaction_charts/helper'; function getYTickFormatter(chart: GenericMetricsChart) { + const max = getMaxY(chart.series); + switch (chart.yUnit) { case 'bytes': { - const max = Math.max( - ...chart.series.map(({ data }) => - Math.max(...data.map(({ y }) => y || 0)) - ) - ); return getFixedByteFormatter(max); } case 'percent': { return (y: Maybe) => asPercent(y || 0, 1); } case 'time': { - return asDuration; + const durationFormatter = getDurationFormatter(max); + return getResponseTimeTickFormatter(durationFormatter); } case 'integer': { return asInteger; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts new file mode 100644 index 0000000000000..c22c326473e2c --- /dev/null +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.test.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + METRIC_JAVA_GC_COUNT, + METRIC_JAVA_GC_TIME, +} from '../../../../../../common/elasticsearch_fieldnames'; +import { Setup } from '../../../../helpers/setup_request'; +import { ChartBase } from '../../../types'; + +import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics'; + +describe('fetchAndTransformGcMetrics', () => { + describe('given "jvm.gc.time"', () => { + it('converts the value to milliseconds', async () => { + const chartBase = {} as unknown as ChartBase; + const response = { + hits: { total: { value: 1 } }, + aggregations: { + per_pool: { + buckets: [ + { + key: 'Copy', + doc_count: 30, + timeseries: { + buckets: [ + { + key_as_string: '2021-10-05T16:03:30.000Z', + key: 1633449810000, + doc_count: 1, + max: { + value: 23750, + }, + derivative: { + value: 11, + }, + value: { + value: 11, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const setup = { + apmEventClient: { search: () => Promise.resolve(response) }, + config: { 'xpack.gc.metricsInterval': 0 }, + } as unknown as Setup; + const fieldName = METRIC_JAVA_GC_TIME; + + const { series } = await fetchAndTransformGcMetrics({ + chartBase, + environment: 'test environment', + fieldName, + kuery: '', + operationName: 'test operation name', + setup, + serviceName: 'test service name', + start: 1633456140000, + end: 1633457078105, + }); + + expect(series[0].data[0].y).toEqual(22000); + }); + }); + + describe('given "jvm.gc.rate"', () => { + it('does not convert the value to milliseconds', async () => { + const chartBase = {} as unknown as ChartBase; + const response = { + hits: { + total: { + value: 62, + }, + }, + aggregations: { + per_pool: { + buckets: [ + { + key: 'Copy', + doc_count: 31, + timeseries: { + buckets: [ + { + key_as_string: '2021-10-05T18:01:30.000Z', + key: 1633456890000, + doc_count: 1, + max: { + value: 815, + }, + derivative: { + value: 4, + }, + value: { + value: 4, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const setup = { + apmEventClient: { search: () => Promise.resolve(response) }, + config: { 'xpack.gc.metricsInterval': 0 }, + } as unknown as Setup; + const fieldName = METRIC_JAVA_GC_COUNT; + + const { series } = await fetchAndTransformGcMetrics({ + chartBase, + environment: 'test environment', + fieldName, + kuery: '', + operationName: 'test operation name', + setup, + serviceName: 'test service name', + start: 1633456140000, + end: 1633457078105, + }); + + expect(series[0].data[0].y).toEqual(8); + }); + }); +}); diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index 8231e4d3c6faa..ba35836452122 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -135,10 +135,17 @@ export async function fetchAndTransformGcMetrics({ const data = timeseriesData.buckets.map((bucket) => { // derivative/value will be undefined for the first hit and if the `max` value is null const bucketValue = bucket.value?.value; - const y = isFiniteNumber(bucketValue) + + const unconvertedY = isFiniteNumber(bucketValue) ? round(bucketValue * (60 / bucketSize), 1) : null; + // convert to milliseconds if we're calculating time, but not for rate + const y = + unconvertedY !== null && fieldName === METRIC_JAVA_GC_TIME + ? unconvertedY * 1000 + : unconvertedY; + return { y, x: bucket.key, diff --git a/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts b/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts index 8d3a18a44f02e..7b621de111ef8 100644 --- a/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts +++ b/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts @@ -39,11 +39,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('contains CPU usage and System memory usage chart data', async () => { expect(chartsResponse.status).to.be(200); expectSnapshot(chartsResponse.body.charts.map((chart) => chart.title)).toMatchInline(` - Array [ - "CPU usage", - "System memory usage", - ] - `); + Array [ + "CPU usage", + "System memory usage", + ] + `); }); describe('CPU usage', () => { @@ -57,25 +57,25 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "System max", - "System average", - "Process max", - "Process average", - ] - `); + Array [ + "System max", + "System average", + "Process max", + "Process average", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0.714, - 0.3877, - 0.75, - 0.2543, - ] - `); + Array [ + 0.714, + 0.3877, + 0.75, + 0.2543, + ] + `); }); }); @@ -91,21 +91,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(systemMemoryUsageChart).to.not.empty(); expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title)) .toMatchInline(` - Array [ - "Max", - "Average", - ] - `); + Array [ + "Max", + "Average", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0.722093920925555, - 0.718173546796348, - ] - `); + Array [ + 0.722093920925555, + 0.718173546796348, + ] + `); }); }); }); @@ -128,16 +128,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct chart data', async () => { expect(chartsResponse.status).to.be(200); expectSnapshot(chartsResponse.body.charts.map((chart) => chart.title)).toMatchInline(` - Array [ - "CPU usage", - "System memory usage", - "Heap Memory", - "Non-Heap Memory", - "Thread Count", - "Garbage collection per minute", - "Garbage collection time spent per minute", - ] - `); + Array [ + "CPU usage", + "System memory usage", + "Heap Memory", + "Non-Heap Memory", + "Thread Count", + "Garbage collection per minute", + "Garbage collection time spent per minute", + ] + `); }); describe('CPU usage', () => { @@ -151,37 +151,37 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "System max", - "System average", - "Process max", - "Process average", - ] - `); + Array [ + "System max", + "System average", + "Process max", + "Process average", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0.203, - 0.178777777777778, - 0.01, - 0.009, - ] - `); + Array [ + 0.203, + 0.178777777777778, + 0.01, + 0.009, + ] + `); }); it('has the correct rate', async () => { const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 0.193, - 0.193, - 0.009, - 0.009, - ] - `); + Array [ + 0.193, + 0.193, + 0.009, + 0.009, + ] + `); }); }); @@ -197,31 +197,31 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(systemMemoryUsageChart).to.not.empty(); expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title)) .toMatchInline(` - Array [ - "Max", - "Average", - ] - `); + Array [ + "Max", + "Average", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0.707924703557837, - 0.705395980841182, - ] - `); + Array [ + 0.707924703557837, + 0.705395980841182, + ] + `); }); it('has the correct rate', async () => { const yValues = systemMemoryUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 0.707924703557837, - 0.707924703557837, - ] - `); + Array [ + 0.707924703557837, + 0.707924703557837, + ] + `); }); }); @@ -236,34 +236,34 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "Avg. used", - "Avg. committed", - "Avg. limit", - ] - `); + Array [ + "Avg. used", + "Avg. committed", + "Avg. limit", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 222501617.777778, - 374341632, - 1560281088, - ] - `); + Array [ + 222501617.777778, + 374341632, + 1560281088, + ] + `); }); it('has the correct rate', async () => { const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 211472896, - 374341632, - 1560281088, - ] - `); + Array [ + 211472896, + 374341632, + 1560281088, + ] + `); }); }); @@ -278,31 +278,31 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "Avg. used", - "Avg. committed", - ] - `); + Array [ + "Avg. used", + "Avg. committed", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 138573397.333333, - 147677639.111111, - ] - `); + Array [ + 138573397.333333, + 147677639.111111, + ] + `); }); it('has the correct rate', async () => { const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 138162752, - 147386368, - ] - `); + Array [ + 138162752, + 147386368, + ] + `); }); }); @@ -317,31 +317,31 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "Avg. count", - "Max count", - ] - `); + Array [ + "Avg. count", + "Max count", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 44.4444444444444, - 45, - ] - `); + Array [ + 44.4444444444444, + 45, + ] + `); }); it('has the correct rate', async () => { const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 44, - 44, - ] - `); + Array [ + 44, + 44, + ] + `); }); }); @@ -356,21 +356,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "G1 Old Generation", - "G1 Young Generation", - ] - `); + Array [ + "G1 Old Generation", + "G1 Young Generation", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0, - 3, - ] - `); + Array [ + 0, + 3, + ] + `); }); }); @@ -385,21 +385,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has correct series', () => { expect(cpuUsageChart).to.not.empty(); expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "G1 Old Generation", - "G1 Young Generation", - ] - `); + Array [ + "G1 Old Generation", + "G1 Young Generation", + ] + `); }); it('has correct series overall values', () => { expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0, - 37.5, - ] - `); + Array [ + 0, + 37500, + ] + `); }); }); }); @@ -419,26 +419,26 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(systemMemoryUsageChart).to.not.empty(); expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title)).toMatchInline(` - Array [ - "Max", - "Average", - ] - `); + Array [ + "Max", + "Average", + ] + `); expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue)) .toMatchInline(` - Array [ - 0.114523896426499, - 0.114002376090415, - ] - `); + Array [ + 0.114523896426499, + 0.114002376090415, + ] + `); const yValues = systemMemoryUsageChart?.series.map((serie) => first(serie.data)?.y); expectSnapshot(yValues).toMatchInline(` - Array [ - 0.11383724014064, - 0.11383724014064, - ] - `); + Array [ + 0.11383724014064, + 0.11383724014064, + ] + `); }); }); } From a054749c7a49c211e5c09dd64b35f76ead569aa7 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Tue, 12 Oct 2021 09:28:37 -0400 Subject: [PATCH 48/73] [Stack Monitoring] ES Overview fix completed recoveries section (#114179) * fix completed recoveries section * fix type * fix type Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pages/elasticsearch/overview.tsx | 5 +- .../public/components/elasticsearch/index.ts | 1 + .../elasticsearch/overview/index.ts | 2 + .../elasticsearch/overview/overview_react.js | 66 ++++++++ .../elasticsearch/shard_activity/index.js | 1 + .../shard_activity/parse_props.js | 14 +- .../shard_activity/shard_activity_react.js | 156 ++++++++++++++++++ 7 files changed, 240 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview_react.js create mode 100644 x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity_react.js diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx index c58aaa5dffb04..d1500d5d9587b 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/overview.tsx @@ -10,7 +10,8 @@ import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { GlobalStateContext } from '../../contexts/global_state_context'; -import { ElasticsearchOverview } from '../../../components/elasticsearch'; +// @ts-ignore +import { ElasticsearchOverviewReact } from '../../../components/elasticsearch'; import { ComponentProps } from '../../route_init'; import { useCharts } from '../../hooks/use_charts'; import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; @@ -78,7 +79,7 @@ export const ElasticsearchOverviewPage: React.FC = ({ clusters } const shardActivityData = shardActivity && filterShardActivityData(shardActivity); // no filter on data = null return ( - + + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js index bcdbbe715f86e..8c0b8b4c9c82d 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js @@ -6,3 +6,4 @@ */ export { ShardActivity } from './shard_activity'; +export { ShardActivityReact } from './shard_activity_react'; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js index 76f22583af0c8..1f0ed47adf387 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js @@ -37,18 +37,26 @@ export const parseProps = (props) => { target, translog, type, + timezone, } = props; const { files, size } = index; - const injector = Legacy.shims.getAngularInjector(); - const timezone = injector.get('config').get('dateFormat:tz'); + + let thisTimezone; + // react version passes timezone while Angular uses injector + if (!timezone) { + const injector = Legacy.shims.getAngularInjector(); + thisTimezone = injector.get('config').get('dateFormat:tz'); + } else { + thisTimezone = timezone; + } return { name: indexName || index.name, shard: `${id} / ${isPrimary ? 'Primary' : 'Replica'}`, relocationType: type === 'PRIMARY_RELOCATION' ? 'Primary Relocation' : normalizeString(type), stage: normalizeString(stage), - startTime: formatDateTimeLocal(startTimeInMillis, timezone), + startTime: formatDateTimeLocal(startTimeInMillis, thisTimezone), totalTime: formatMetric(Math.floor(totalTimeInMillis / 1000), '00:00:00'), isCopiedFromPrimary: !isPrimary || type === 'PRIMARY_RELOCATION', sourceName: source.name === undefined ? 'n/a' : source.name, diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity_react.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity_react.js new file mode 100644 index 0000000000000..cc219ff0fff32 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity_react.js @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { Fragment } from 'react'; +import { EuiText, EuiTitle, EuiLink, EuiSpacer, EuiSwitch } from '@elastic/eui'; +import { EuiMonitoringTable } from '../../table'; +import { RecoveryIndex } from './recovery_index'; +import { TotalTime } from './total_time'; +import { SourceDestination } from './source_destination'; +import { FilesProgress, BytesProgress, TranslogProgress } from './progress'; +import { parseProps } from './parse_props'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; + +const columns = [ + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.indexTitle', { + defaultMessage: 'Index', + }), + field: 'name', + render: (_name, shard) => , + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.stageTitle', { + defaultMessage: 'Stage', + }), + field: 'stage', + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.totalTimeTitle', { + defaultMessage: 'Total Time', + }), + field: null, + render: (shard) => , + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.sourceDestinationTitle', { + defaultMessage: 'Source / Destination', + }), + field: null, + render: (shard) => , + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.filesTitle', { + defaultMessage: 'Files', + }), + field: null, + render: (shard) => , + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.bytesTitle', { + defaultMessage: 'Bytes', + }), + field: null, + render: (shard) => , + }, + { + name: i18n.translate('xpack.monitoring.kibana.shardActivity.translogTitle', { + defaultMessage: 'Translog', + }), + field: null, + render: (shard) => , + }, +]; + +export const ShardActivityReact = (props) => { + const { + data: rawData, + sorting, + pagination, + onTableChange, + toggleShardActivityHistory, + showShardActivityHistory, + } = props; + const { services } = useKibana(); + const timezone = services.uiSettings?.get('dateFormat:tz'); + const getNoDataMessage = () => { + if (showShardActivityHistory) { + return i18n.translate('xpack.monitoring.elasticsearch.shardActivity.noDataMessage', { + defaultMessage: + 'There are no historical shard activity records for the selected time range.', + }); + } + return ( + + +
+ + + + ), + }} + /> +
+ ); + }; + + const rows = rawData.map((data) => parseProps({ ...data, timezone })); + + return ( + + + +

+ +

+
+
+ + + } + onChange={toggleShardActivityHistory} + checked={showShardActivityHistory} + /> + + +
+ ); +}; From 9e42b32015cd0bdca0aecbfc93c3bfc1b1404e1a Mon Sep 17 00:00:00 2001 From: Sandra G Date: Tue, 12 Oct 2021 09:32:52 -0400 Subject: [PATCH 49/73] [Stack Monitoring] Add breadcrumbs to ES pages after migrating from Angular (#114555) * add breadcrumbs * fix bad merge * fix types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pages/elasticsearch/ccr_page.tsx | 13 +++++++++-- .../pages/elasticsearch/ccr_shard_page.tsx | 22 +++++++++++++++--- .../elasticsearch/index_advanced_page.tsx | 21 +++++++++++++++-- .../pages/elasticsearch/index_page.tsx | 20 ++++++++++++++-- .../pages/elasticsearch/indices_page.tsx | 14 +++++++++-- .../pages/elasticsearch/ml_jobs_page.tsx | 14 +++++++++-- .../elasticsearch/node_advanced_page.tsx | 23 ++++++++++++++++--- .../pages/elasticsearch/node_page.tsx | 22 +++++++++++++++--- 8 files changed, 130 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx index 8a9a736286c3f..cb37705c959aa 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_page.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; @@ -18,7 +18,7 @@ import { SetupModeContext } from '../../../components/setup_mode/setup_mode_cont import { AlertsByName } from '../../../alerts/types'; import { fetchAlerts } from '../../../lib/fetch_alerts'; import { ELASTICSEARCH_SYSTEM_ID, RULE_CCR_READ_EXCEPTIONS } from '../../../../common/constants'; - +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; interface SetupModeProps { setupMode: any; flyoutComponent: any; @@ -27,6 +27,7 @@ interface SetupModeProps { export const ElasticsearchCcrPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { services } = useKibana<{ data: any }>(); const clusterUuid = globalState.cluster_uuid; @@ -37,6 +38,14 @@ export const ElasticsearchCcrPage: React.FC = ({ clusters }) => const [data, setData] = useState({} as any); const [alerts, setAlerts] = useState({}); + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + }); + } + }, [cluster, generateBreadcrumbs]); + const title = i18n.translate('xpack.monitoring.elasticsearch.ccr.title', { defaultMessage: 'Elasticsearch - Ccr', }); diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx index 21f9fd10f0806..29cf9ade8d997 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ccr_shard_page.tsx @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import { find } from 'lodash'; import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; import { PageTemplate } from '../page_template'; @@ -19,6 +20,7 @@ import { SetupModeContext } from '../../../components/setup_mode/setup_mode_cont import { AlertsByName } from '../../../alerts/types'; import { fetchAlerts } from '../../../lib/fetch_alerts'; import { ELASTICSEARCH_SYSTEM_ID, RULE_CCR_READ_EXCEPTIONS } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; interface SetupModeProps { setupMode: any; @@ -26,14 +28,28 @@ interface SetupModeProps { bottomBarComponent: any; } -export const ElasticsearchCcrShardPage: React.FC = () => { +export const ElasticsearchCcrShardPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); const { services } = useKibana<{ data: any }>(); + const [data, setData] = useState({} as any); const { index, shardId }: { index: string; shardId: string } = useParams(); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const clusterUuid = globalState.cluster_uuid; + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + name: 'ccr', + instance: `Index: ${index} Shard: ${shardId}`, + }); + } + }, [cluster, generateBreadcrumbs, index, shardId]); const ccs = globalState.ccs; - const [data, setData] = useState({} as any); const [alerts, setAlerts] = useState({}); const title = i18n.translate('xpack.monitoring.elasticsearch.ccr.shard.title', { diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx index 86dba4e2f921c..f2f2ec36b7cd9 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_advanced_page.tsx @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; +import { find } from 'lodash'; import { useParams } from 'react-router-dom'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { GlobalStateContext } from '../../contexts/global_state_context'; @@ -19,9 +20,11 @@ import { AdvancedIndex } from '../../../components/elasticsearch/index/advanced' import { AlertsByName } from '../../../alerts/types'; import { fetchAlerts } from '../../../lib/fetch_alerts'; import { ELASTICSEARCH_SYSTEM_ID, RULE_LARGE_SHARD_SIZE } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; -export const ElasticsearchIndexAdvancedPage: React.FC = () => { +export const ElasticsearchIndexAdvancedPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { services } = useKibana<{ data: any }>(); const { index }: { index: string } = useParams(); const { zoomInfo, onBrush } = useCharts(); @@ -29,6 +32,20 @@ export const ElasticsearchIndexAdvancedPage: React.FC = () => { const [data, setData] = useState({} as any); const [alerts, setAlerts] = useState({}); + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + name: 'indices', + instance: index, + }); + } + }, [cluster, generateBreadcrumbs, index]); + const title = i18n.translate('xpack.monitoring.elasticsearch.index.advanced.title', { defaultMessage: 'Elasticsearch - Indices - {indexName} - Advanced', values: { diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx index b73fee0c963cc..8e70a99e67914 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { useParams } from 'react-router-dom'; +import { find } from 'lodash'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { GlobalStateContext } from '../../contexts/global_state_context'; // @ts-ignore @@ -23,9 +24,11 @@ import { labels } from '../../../components/elasticsearch/shard_allocation/lib/l import { AlertsByName } from '../../../alerts/types'; import { fetchAlerts } from '../../../lib/fetch_alerts'; import { ELASTICSEARCH_SYSTEM_ID, RULE_LARGE_SHARD_SIZE } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; -export const ElasticsearchIndexPage: React.FC = () => { +export const ElasticsearchIndexPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { services } = useKibana<{ data: any }>(); const { index }: { index: string } = useParams(); const { zoomInfo, onBrush } = useCharts(); @@ -34,6 +37,19 @@ export const ElasticsearchIndexPage: React.FC = () => { const [indexLabel, setIndexLabel] = useState(labels.index as any); const [nodesByIndicesData, setNodesByIndicesData] = useState([]); const [alerts, setAlerts] = useState({}); + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + name: 'indices', + instance: index, + }); + } + }, [cluster, generateBreadcrumbs, index]); const title = i18n.translate('xpack.monitoring.elasticsearch.index.overview.title', { defaultMessage: 'Elasticsearch - Indices - {indexName} - Overview', diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/indices_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/indices_page.tsx index 44e01cbf66ff3..277bde2ac35cb 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/indices_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/indices_page.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; @@ -19,16 +19,18 @@ import { useLocalStorage } from '../../hooks/use_local_storage'; import { AlertsByName } from '../../../alerts/types'; import { fetchAlerts } from '../../../lib/fetch_alerts'; import { ELASTICSEARCH_SYSTEM_ID, RULE_LARGE_SHARD_SIZE } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; export const ElasticsearchIndicesPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { services } = useKibana<{ data: any }>(); const { getPaginationTableProps } = useTable('elasticsearch.indices'); const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; const cluster = find(clusters, { cluster_uuid: clusterUuid, - }); + }) as any; const [data, setData] = useState({} as any); const [showSystemIndices, setShowSystemIndices] = useLocalStorage( 'showSystemIndices', @@ -36,6 +38,14 @@ export const ElasticsearchIndicesPage: React.FC = ({ clusters }) ); const [alerts, setAlerts] = useState({}); + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + }); + } + }, [cluster, generateBreadcrumbs]); + const title = i18n.translate('xpack.monitoring.elasticsearch.indices.routeTitle', { defaultMessage: 'Elasticsearch - Indices', }); diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ml_jobs_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ml_jobs_page.tsx index 7edf15886cc20..b97007f1c1462 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ml_jobs_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ml_jobs_page.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; import { ElasticsearchTemplate } from './elasticsearch_template'; @@ -16,6 +16,7 @@ import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; import { useTable } from '../../hooks/use_table'; import type { MLJobs } from '../../../types'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants'; interface SetupModeProps { @@ -26,13 +27,22 @@ interface SetupModeProps { export const ElasticsearchMLJobsPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { services } = useKibana<{ data: any }>(); const { getPaginationTableProps } = useTable('elasticsearch.mlJobs'); const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; const cluster = find(clusters, { cluster_uuid: clusterUuid, - }); + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + }); + } + }, [cluster, generateBreadcrumbs]); const [data, setData] = useState({} as any); const title = i18n.translate('xpack.monitoring.elasticsearch.mlJobs.routeTitle', { diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_advanced_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_advanced_page.tsx index 9c0f5f4627b01..820eb2fb20cd8 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_advanced_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_advanced_page.tsx @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ItemTemplate } from './item_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; @@ -24,19 +25,35 @@ import { RULE_DISK_USAGE, RULE_MEMORY_USAGE, } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; -export const ElasticsearchNodeAdvancedPage: React.FC = () => { +export const ElasticsearchNodeAdvancedPage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { zoomInfo, onBrush } = useCharts(); + const [data, setData] = useState({} as any); const { node }: { node: string } = useParams(); const { services } = useKibana<{ data: any }>(); const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; - const [data, setData] = useState({} as any); const [alerts, setAlerts] = useState({}); + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + name: 'nodes', + instance: data?.nodeSummary?.name, + }); + } + }, [cluster, generateBreadcrumbs, data?.nodeSummary?.name]); + const title = i18n.translate('xpack.monitoring.elasticsearch.node.advanced.title', { defaultMessage: 'Elasticsearch - Nodes - {nodeName} - Advanced', values: { diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx index f5ae4dc29b28e..b2d6fb94183ec 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useContext, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback, useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ItemTemplate } from './item_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; @@ -30,9 +31,11 @@ import { RULE_DISK_USAGE, RULE_MEMORY_USAGE, } from '../../../../common/constants'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; -export const ElasticsearchNodePage: React.FC = () => { +export const ElasticsearchNodePage: React.FC = ({ clusters }) => { const globalState = useContext(GlobalStateContext); + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); const { zoomInfo, onBrush } = useCharts(); const [showSystemIndices, setShowSystemIndices] = useLocalStorage( 'showSystemIndices', @@ -42,10 +45,23 @@ export const ElasticsearchNodePage: React.FC = () => { const { node }: { node: string } = useParams(); const { services } = useKibana<{ data: any }>(); + const [data, setData] = useState({} as any); const clusterUuid = globalState.cluster_uuid; + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inElasticsearch: true, + name: 'nodes', + instance: data?.nodeSummary?.name, + }); + } + }, [cluster, generateBreadcrumbs, data?.nodeSummary?.name]); const ccs = globalState.ccs; - const [data, setData] = useState({} as any); const [nodesByIndicesData, setNodesByIndicesData] = useState([]); const title = i18n.translate('xpack.monitoring.elasticsearch.node.overview.title', { From d37cf3045bed23a05c491a4eebe9928f5b054be5 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Tue, 12 Oct 2021 06:35:55 -0700 Subject: [PATCH 50/73] [Reporting] Remove unused settings for 8.0 (#114216) * [Reporting] Remove unused settings for 8.0 * add helpful version comments Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/reporting/server/config/index.ts | 10 +++------- x-pack/plugins/reporting/server/config/schema.ts | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index c7afdb22f8bdb..f8fa47bc00bb0 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -17,13 +17,9 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { poll: true, roles: true }, schema: ConfigSchema, deprecations: ({ unused }) => [ - unused('capture.browser.chromium.maxScreenshotDimension'), - unused('capture.concurrency'), - unused('capture.settleTime'), - unused('capture.timeout'), - unused('poll.jobCompletionNotifier.intervalErrorMultiplier'), - unused('poll.jobsRefresh.intervalErrorMultiplier'), - unused('kibanaApp'), + unused('capture.browser.chromium.maxScreenshotDimension'), // unused since 7.8 + unused('poll.jobCompletionNotifier.intervalErrorMultiplier'), // unused since 7.10 + unused('poll.jobsRefresh.intervalErrorMultiplier'), // unused since 7.10 (settings, fromPath, addDeprecation) => { const reporting = get(settings, fromPath); if (reporting?.index) { diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index affd8b7bee7ff..832cf6c28e1fa 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -160,11 +160,11 @@ const RolesSchema = schema.object({ const PollSchema = schema.object({ jobCompletionNotifier: schema.object({ interval: schema.number({ defaultValue: 10000 }), - intervalErrorMultiplier: schema.number({ defaultValue: 5 }), // unused + intervalErrorMultiplier: schema.number({ defaultValue: 5 }), // deprecated as unused since 7.10 }), jobsRefresh: schema.object({ interval: schema.number({ defaultValue: 5000 }), - intervalErrorMultiplier: schema.number({ defaultValue: 5 }), // unused + intervalErrorMultiplier: schema.number({ defaultValue: 5 }), // deprecated as unused since 7.10 }), }); From 4f893931248fbdf6bbfad3459b0fd33404f65697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 12 Oct 2021 15:37:50 +0200 Subject: [PATCH 51/73] [APM] Add Table of contents to data model docs (#114608) --- x-pack/plugins/apm/dev_docs/apm_queries.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/dev_docs/apm_queries.md b/x-pack/plugins/apm/dev_docs/apm_queries.md index 8508e5a173c85..0fbcd4fc1c8a8 100644 --- a/x-pack/plugins/apm/dev_docs/apm_queries.md +++ b/x-pack/plugins/apm/dev_docs/apm_queries.md @@ -1,7 +1,17 @@ -# Data model +### Table of Contents + - [Transactions](#transactions) + - [System metrics](#system-metrics) + - [Transaction breakdown metrics](#transaction-breakdown-metrics) + - [Span breakdown metrics](#span-breakdown-metrics) + - [Service destination metrics](#service-destination-metrics) + - [Common filters](#common-filters) + +--- + +### Data model Elastic APM agents capture different types of information from within their instrumented applications. These are known as events, and can be spans, transactions, errors, or metrics. You can find more information [here](https://www.elastic.co/guide/en/apm/get-started/current/apm-data-model.html). -# Running examples +### Running examples You can run the example queries on the [edge cluster](https://edge-oblt.elastic.dev/) or any another cluster that contains APM data. # Transactions @@ -307,7 +317,7 @@ The above example is overly simplified. In reality [we do a bit more](https://gi -# Transaction breakdown metrics (`transaction_breakdown`) +# Transaction breakdown metrics A pre-aggregations of transaction documents where `transaction.breakdown.count` is the number of original transactions. @@ -327,7 +337,7 @@ Noteworthy fields: `transaction.name`, `transaction.type` } ``` -# Span breakdown metrics (`span_breakdown`) +# Span breakdown metrics A pre-aggregations of span documents where `span.self_time.count` is the number of original spans. Measures the "self-time" for a span type, and optional subtype, within a transaction group. @@ -482,7 +492,7 @@ GET apm-*-metric-*,metrics-apm*/_search?terminate_after=1000 } ``` -## Common filters +# Common filters Most Elasticsearch queries will need to have one or more filters. There are a couple of reasons for adding filters: From afe81bb1a2a8da526a1f42f19e442c32e2ab0fd0 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 12 Oct 2021 15:49:17 +0200 Subject: [PATCH 52/73] [Reporting] Fix missing force now behaviour for v2 reports (#114516) * fix missing force now behaviour for v2 reports * added jest test * updated jest test snapshot to match removal of forceNow injection from locator params Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/export_types/common/index.ts | 1 - .../export_types/common/set_force_now.ts | 24 ---------- .../v2/get_full_redirect_app_url.test.ts | 45 +++++++++++++++++++ .../common/v2/get_full_redirect_app_url.ts | 7 ++- .../export_types/png_v2/execute_job.test.ts | 6 +-- .../server/export_types/png_v2/execute_job.ts | 5 +-- .../printable_pdf_v2/execute_job.ts | 3 +- .../printable_pdf_v2/lib/generate_pdf.ts | 5 ++- 8 files changed, 60 insertions(+), 36 deletions(-) delete mode 100644 x-pack/plugins/reporting/server/export_types/common/set_force_now.ts create mode 100644 x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.test.ts diff --git a/x-pack/plugins/reporting/server/export_types/common/index.ts b/x-pack/plugins/reporting/server/export_types/common/index.ts index 09d3236fa7b54..c35dcb5344e21 100644 --- a/x-pack/plugins/reporting/server/export_types/common/index.ts +++ b/x-pack/plugins/reporting/server/export_types/common/index.ts @@ -12,7 +12,6 @@ export { omitBlockedHeaders } from './omit_blocked_headers'; export { validateUrls } from './validate_urls'; export { generatePngObservableFactory } from './generate_png'; export { getCustomLogo } from './get_custom_logo'; -export { setForceNow } from './set_force_now'; export interface TimeRangeParams { min?: Date | string | number | null; diff --git a/x-pack/plugins/reporting/server/export_types/common/set_force_now.ts b/x-pack/plugins/reporting/server/export_types/common/set_force_now.ts deleted file mode 100644 index b4f4b1b0ace05..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/common/set_force_now.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { LocatorParams } from '../../../common/types'; - -/** - * Add `forceNow` to {@link LocatorParams['params']} to enable clients to set the time appropriately when - * reporting navigates to the page in Chromium. - */ -export const setForceNow = - (forceNow: string) => - (locator: LocatorParams): LocatorParams => { - return { - ...locator, - params: { - ...locator.params, - forceNow, - }, - }; - }; diff --git a/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.test.ts b/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.test.ts new file mode 100644 index 0000000000000..7a2ec5b83e7f4 --- /dev/null +++ b/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.test.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { get } from 'lodash'; +import { ReportingConfig } from '../../../config/config'; +import { getFullRedirectAppUrl } from './get_full_redirect_app_url'; + +describe('getFullRedirectAppUrl', () => { + let config: ReportingConfig; + + beforeEach(() => { + const values = { + server: { + basePath: 'test', + }, + kibanaServer: { + protocol: 'http', + hostname: 'localhost', + port: '1234', + }, + }; + config = { + get: jest.fn((...args: string[]) => get(values, args)), + kbnConfig: { + get: jest.fn((...args: string[]) => get(values, args)), + }, + }; + }); + + test('smoke test', () => { + expect(getFullRedirectAppUrl(config, 'test', undefined)).toBe( + 'http://localhost:1234/test/s/test/app/management/insightsAndAlerting/reporting/r' + ); + }); + + test('adding forceNow', () => { + expect(getFullRedirectAppUrl(config, 'test', 'TEST with a space')).toBe( + 'http://localhost:1234/test/s/test/app/management/insightsAndAlerting/reporting/r?forceNow=TEST%20with%20a%20space' + ); + }); +}); diff --git a/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.ts b/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.ts index bb640eff667e9..9c329db64fa1a 100644 --- a/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.ts +++ b/x-pack/plugins/reporting/server/export_types/common/v2/get_full_redirect_app_url.ts @@ -10,7 +10,11 @@ import { ReportingConfig } from '../../..'; import { getRedirectAppPath } from '../../../../common/constants'; import { buildKibanaPath } from '../../../../common/build_kibana_path'; -export function getFullRedirectAppUrl(config: ReportingConfig, spaceId?: string) { +export function getFullRedirectAppUrl( + config: ReportingConfig, + spaceId?: string, + forceNow?: string +) { const [basePath, protocol, hostname, port] = [ config.kbnConfig.get('server', 'basePath'), config.get('kibanaServer', 'protocol'), @@ -29,5 +33,6 @@ export function getFullRedirectAppUrl(config: ReportingConfig, spaceId?: string) hostname, port, pathname: path, + query: forceNow ? { forceNow } : undefined, }); } diff --git a/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.test.ts b/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.test.ts index e57eab382468c..3cf3c057e7b9c 100644 --- a/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.test.ts +++ b/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.test.ts @@ -102,12 +102,10 @@ test(`passes browserTimezone to generatePng`, async () => { "warning": [Function], }, Array [ - "localhost:80undefined/app/management/insightsAndAlerting/reporting/r", + "localhost:80undefined/app/management/insightsAndAlerting/reporting/r?forceNow=test", Object { "id": "test", - "params": Object { - "forceNow": "test", - }, + "params": Object {}, "version": "test", }, ], diff --git a/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.ts b/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.ts index 5c2cc66d3d3aa..a7478de1cc96e 100644 --- a/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/png_v2/execute_job.ts @@ -16,7 +16,6 @@ import { getConditionalHeaders, omitBlockedHeaders, generatePngObservableFactory, - setForceNow, } from '../common'; import { getFullRedirectAppUrl } from '../common/v2/get_full_redirect_app_url'; import { TaskPayloadPNGV2 } from './types'; @@ -38,8 +37,8 @@ export const runTaskFnFactory: RunTaskFnFactory> = map((decryptedHeaders) => omitBlockedHeaders(decryptedHeaders)), map((filteredHeaders) => getConditionalHeaders(config, filteredHeaders)), mergeMap((conditionalHeaders) => { - const url = getFullRedirectAppUrl(config, job.spaceId); - const [locatorParams] = job.locatorParams.map(setForceNow(job.forceNow)); + const url = getFullRedirectAppUrl(config, job.spaceId, job.forceNow); + const [locatorParams] = job.locatorParams; apmGetAssets?.end(); diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/execute_job.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/execute_job.ts index e44f5e98fa4fe..2c553295aa840 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/execute_job.ts @@ -16,7 +16,6 @@ import { getConditionalHeaders, omitBlockedHeaders, getCustomLogo, - setForceNow, } from '../common'; import { generatePdfObservableFactory } from './lib/generate_pdf'; import { TaskPayloadPDFV2 } from './types'; @@ -50,7 +49,7 @@ export const runTaskFnFactory: RunTaskFnFactory> = jobLogger, job, title, - locatorParams.map(setForceNow(job.forceNow)), + locatorParams, browserTimezone, conditionalHeaders, layout, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/lib/generate_pdf.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/lib/generate_pdf.ts index 424a347876a1d..9fb31a1104279 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/lib/generate_pdf.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf_v2/lib/generate_pdf.ts @@ -56,7 +56,10 @@ export async function generatePdfObservableFactory(reporting: ReportingCore) { /** * For each locator we get the relative URL to the redirect app */ - const urls = locatorParams.map(() => getFullRedirectAppUrl(reporting.getConfig(), job.spaceId)); + const urls = locatorParams.map(() => + getFullRedirectAppUrl(reporting.getConfig(), job.spaceId, job.forceNow) + ); + const screenshots$ = getScreenshots$(captureConfig, browserDriverFactory, { logger, urlsOrUrlLocatorTuples: zip(urls, locatorParams) as UrlOrUrlLocatorTuple[], From bc96e408c9a852b3aa78fbea283a6e6ff595c1e9 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Tue, 12 Oct 2021 07:02:03 -0700 Subject: [PATCH 53/73] Changes `rewriteBasePath` core config deprecation level to warning (#114566) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/config/deprecation/core_deprecations.test.ts | 7 ++++++- src/core/server/config/deprecation/core_deprecations.ts | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/server/config/deprecation/core_deprecations.test.ts b/src/core/server/config/deprecation/core_deprecations.test.ts index e08f2216f5cbe..99fe6c7cd1dc4 100644 --- a/src/core/server/config/deprecation/core_deprecations.test.ts +++ b/src/core/server/config/deprecation/core_deprecations.test.ts @@ -54,7 +54,7 @@ describe('core deprecations', () => { describe('rewriteBasePath', () => { it('logs a warning is server.basePath is set and server.rewriteBasePath is not', () => { - const { messages } = applyCoreDeprecations({ + const { messages, levels } = applyCoreDeprecations({ server: { basePath: 'foo', }, @@ -64,6 +64,11 @@ describe('core deprecations', () => { "You should set server.basePath along with server.rewriteBasePath. Starting in 7.0, Kibana will expect that all requests start with server.basePath rather than expecting you to rewrite the requests in your reverse proxy. Set server.rewriteBasePath to false to preserve the current behavior and silence this warning.", ] `); + expect(levels).toMatchInlineSnapshot(` + Array [ + "warning", + ] + `); }); it('does not log a warning if both server.basePath and server.rewriteBasePath are unset', () => { diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index 5adbb338b42e4..79fb2aac60da4 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -16,6 +16,7 @@ const rewriteBasePathDeprecation: ConfigDeprecation = (settings, fromPath, addDe 'will expect that all requests start with server.basePath rather than expecting you to rewrite ' + 'the requests in your reverse proxy. Set server.rewriteBasePath to false to preserve the ' + 'current behavior and silence this warning.', + level: 'warning', correctiveActions: { manualSteps: [ `Set 'server.rewriteBasePath' in the config file, CLI flag, or environment variable (in Docker only).`, From d5d364724bb6da744c5708a797a3358040cfc318 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 12 Oct 2021 16:32:40 +0200 Subject: [PATCH 54/73] [Exploratory view] Fix auto apply on date change (#114251) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/date_range_picker.tsx | 10 +- .../configurations/lens_attributes.ts | 6 +- .../exploratory_view/exploratory_view.tsx | 6 +- .../exploratory_view/header/header.test.tsx | 5 +- .../shared/exploratory_view/header/header.tsx | 11 +- .../hooks/use_lens_attributes.ts | 2 +- .../hooks/use_series_storage.tsx | 2 +- .../hooks/use_time_range.test.tsx | 108 ++++++++++++++++++ .../exploratory_view/hooks/use_time_range.ts | 66 +++++++++++ .../exploratory_view/lens_embeddable.tsx | 42 +------ 10 files changed, 194 insertions(+), 64 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.ts diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx index 643f01d570ead..5529f28927028 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/date_range_picker.tsx @@ -15,7 +15,7 @@ import { useUiSetting } from '../../../../../../../../src/plugins/kibana_react/p import { SeriesUrl } from '../types'; import { ReportTypes } from '../configurations/constants'; -export const parseAbsoluteDate = (date: string, options = {}) => { +export const parseRelativeDate = (date: string, options = {}) => { return DateMath.parse(date, options)!; }; export function DateRangePicker({ seriesId, series }: { seriesId: number; series: SeriesUrl }) { @@ -27,12 +27,12 @@ export function DateRangePicker({ seriesId, series }: { seriesId: number; series const { from: mainFrom, to: mainTo } = firstSeries!.time; - const startDate = parseAbsoluteDate(seriesFrom ?? mainFrom)!; - const endDate = parseAbsoluteDate(seriesTo ?? mainTo, { roundUp: true })!; + const startDate = parseRelativeDate(seriesFrom ?? mainFrom)!; + const endDate = parseRelativeDate(seriesTo ?? mainTo, { roundUp: true })!; const getTotalDuration = () => { - const mainStartDate = parseAbsoluteDate(mainFrom)!; - const mainEndDate = parseAbsoluteDate(mainTo, { roundUp: true })!; + const mainStartDate = parseRelativeDate(mainFrom)!; + const mainEndDate = parseRelativeDate(mainTo, { roundUp: true })!; return mainEndDate.diff(mainStartDate, 'millisecond'); }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index 428ef54277fe2..fa5a8beb0087d 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -41,7 +41,7 @@ import { } from './constants'; import { ColumnFilter, SeriesConfig, UrlFilter, URLReportDefinition } from '../types'; import { PersistableFilter } from '../../../../../../lens/common'; -import { parseAbsoluteDate } from '../components/date_range_picker'; +import { parseRelativeDate } from '../components/date_range_picker'; import { getDistributionInPercentageColumn } from './lens_columns/overall_column'; function getLayerReferenceName(layerId: string) { @@ -544,11 +544,11 @@ export class LensAttributes { time: { from }, } = layerConfig; - const inDays = Math.abs(parseAbsoluteDate(mainFrom).diff(parseAbsoluteDate(from), 'days')); + const inDays = Math.abs(parseRelativeDate(mainFrom).diff(parseRelativeDate(from), 'days')); if (inDays > 1) { return inDays + 'd'; } - const inHours = Math.abs(parseAbsoluteDate(mainFrom).diff(parseAbsoluteDate(from), 'hours')); + const inHours = Math.abs(parseRelativeDate(mainFrom).diff(parseRelativeDate(from), 'hours')); if (inHours === 0) { return null; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index faf064868dec5..9870d88d1220a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -96,11 +96,7 @@ export function ExploratoryView({ {lens ? ( <> - + + ); getByText('Refresh'); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx index 59b146ae9af1a..181c8342b87af 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx @@ -11,21 +11,18 @@ import { EuiBetaBadge, EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@el import { TypedLensByValueInput } from '../../../../../../lens/public'; import { useSeriesStorage } from '../hooks/use_series_storage'; import { LastUpdated } from './last_updated'; -import { combineTimeRanges } from '../lens_embeddable'; import { ExpViewActionMenu } from '../components/action_menu'; +import { useExpViewTimeRange } from '../hooks/use_time_range'; interface Props { - seriesId?: number; lastUpdated?: number; lensAttributes: TypedLensByValueInput['attributes'] | null; } -export function ExploratoryViewHeader({ seriesId, lensAttributes, lastUpdated }: Props) { - const { getSeries, allSeries, setLastRefresh, reportType } = useSeriesStorage(); +export function ExploratoryViewHeader({ lensAttributes, lastUpdated }: Props) { + const { setLastRefresh } = useSeriesStorage(); - const series = seriesId ? getSeries(seriesId) : undefined; - - const timeRange = combineTimeRanges(reportType, allSeries, series); + const timeRange = useExpViewTimeRange(); return ( <> diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts index 23eee140b68cf..dbf36777b536f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts @@ -94,7 +94,7 @@ export const useLensAttributes = (): TypedLensByValueInput['attributes'] | null if (isEmpty(indexPatterns) || isEmpty(allSeries) || !reportType) { return null; } - + // we only use the data from url to apply, since that get's updated to apply changes const allSeriesT: AllSeries = convertAllShortSeries(storage.get(allSeriesKey) ?? []); const layerConfigs = getLayerConfigs(allSeriesT, reportType, theme, indexPatterns); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx index 83042876db2ae..e71c66ba1f11b 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx @@ -45,7 +45,7 @@ export function convertAllShortSeries(allShortSeries: AllShortSeries) { } export const allSeriesKey = 'sr'; -const reportTypeKey = 'reportType'; +export const reportTypeKey = 'reportType'; export function UrlStorageContextProvider({ children, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.test.tsx new file mode 100644 index 0000000000000..38534b1c79e3e --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.test.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { allSeriesKey, reportTypeKey, UrlStorageContextProvider } from './use_series_storage'; +import { renderHook } from '@testing-library/react-hooks'; +import { useExpViewTimeRange } from './use_time_range'; +import { ReportTypes } from '../configurations/constants'; +import { createKbnUrlStateStorage } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { TRANSACTION_DURATION } from '../configurations/constants/elasticsearch_fieldnames'; + +const mockSingleSeries = [ + { + name: 'performance-distribution', + dataType: 'ux', + breakdown: 'user_agent.name', + time: { from: 'now-15m', to: 'now' }, + selectedMetricField: TRANSACTION_DURATION, + reportDefinitions: { 'service.name': ['elastic-co'] }, + }, +]; + +const mockMultipleSeries = [ + ...mockSingleSeries, + { + name: 'kpi-over-time', + dataType: 'synthetics', + breakdown: 'user_agent.name', + time: { from: 'now-30m', to: 'now' }, + selectedMetricField: TRANSACTION_DURATION, + reportDefinitions: { 'service.name': ['elastic-co'] }, + }, +]; + +describe('useExpViewTimeRange', function () { + const storage = createKbnUrlStateStorage({ useHash: false }); + + function Wrapper({ children }: { children: JSX.Element }) { + return {children}; + } + it('should return expected result when there is one series', async function () { + await storage.set(allSeriesKey, mockSingleSeries); + await storage.set(reportTypeKey, ReportTypes.KPI); + + const { result } = renderHook(() => useExpViewTimeRange(), { + wrapper: Wrapper, + }); + + expect(result.current).toEqual({ + from: 'now-15m', + to: 'now', + }); + }); + + it('should return expected result when there are multiple KPI series', async function () { + await storage.set(allSeriesKey, mockMultipleSeries); + await storage.set(reportTypeKey, ReportTypes.KPI); + + const { result } = renderHook(() => useExpViewTimeRange(), { + wrapper: Wrapper, + }); + + expect(result.current).toEqual({ + from: 'now-15m', + to: 'now', + }); + }); + + it('should return expected result when there are multiple distribution series with relative dates', async function () { + await storage.set(allSeriesKey, mockMultipleSeries); + await storage.set(reportTypeKey, ReportTypes.DISTRIBUTION); + + const { result } = renderHook(() => useExpViewTimeRange(), { + wrapper: Wrapper, + }); + + expect(result.current).toEqual({ + from: 'now-30m', + to: 'now', + }); + }); + + it('should return expected result when there are multiple distribution series with absolute dates', async function () { + // from:'2021-10-11T09:55:39.551Z',to:'2021-10-11T10:55:41.516Z'))) + mockMultipleSeries[0].time.from = '2021-10-11T09:55:39.551Z'; + mockMultipleSeries[0].time.to = '2021-10-11T11:55:41.516Z'; + + mockMultipleSeries[1].time.from = '2021-01-11T09:55:39.551Z'; + mockMultipleSeries[1].time.to = '2021-10-11T10:55:41.516Z'; + + await storage.set(allSeriesKey, mockMultipleSeries); + await storage.set(reportTypeKey, ReportTypes.DISTRIBUTION); + + const { result } = renderHook(() => useExpViewTimeRange(), { + wrapper: Wrapper, + }); + + expect(result.current).toEqual({ + from: '2021-01-11T09:55:39.551Z', + to: '2021-10-11T11:55:41.516Z', + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.ts new file mode 100644 index 0000000000000..60087cfd0330c --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_time_range.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isEmpty } from 'lodash'; +import { useMemo } from 'react'; +import { + AllSeries, + allSeriesKey, + convertAllShortSeries, + useSeriesStorage, +} from './use_series_storage'; + +import { ReportViewType, SeriesUrl } from '../types'; +import { ReportTypes } from '../configurations/constants'; +import { parseRelativeDate } from '../components/date_range_picker'; + +export const combineTimeRanges = ( + reportType: ReportViewType, + allSeries: SeriesUrl[], + firstSeries?: SeriesUrl +) => { + let to: string = ''; + let from: string = ''; + + if (reportType === ReportTypes.KPI) { + return firstSeries?.time; + } + + allSeries.forEach((series) => { + if ( + series.dataType && + series.selectedMetricField && + !isEmpty(series.reportDefinitions) && + series.time + ) { + const seriesFrom = parseRelativeDate(series.time.from)!; + const seriesTo = parseRelativeDate(series.time.to, { roundUp: true })!; + + if (!to || seriesTo > parseRelativeDate(to, { roundUp: true })) { + to = series.time.to; + } + if (!from || seriesFrom < parseRelativeDate(from)) { + from = series.time.from; + } + } + }); + + return { to, from }; +}; +export const useExpViewTimeRange = () => { + const { storage, reportType, lastRefresh, firstSeries } = useSeriesStorage(); + + return useMemo(() => { + // we only use the data from url to apply, since that get updated to apply changes + const allSeriesFromUrl: AllSeries = convertAllShortSeries(storage.get(allSeriesKey) ?? []); + const firstSeriesT = allSeriesFromUrl?.[0]; + + return firstSeriesT ? combineTimeRanges(reportType, allSeriesFromUrl, firstSeriesT) : undefined; + // we want to keep last refresh in dependencies to force refresh + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [reportType, storage, lastRefresh, firstSeries]); +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx index 9e4d9486dc155..235790e72862c 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx @@ -8,50 +8,16 @@ import { i18n } from '@kbn/i18n'; import React, { Dispatch, SetStateAction, useCallback } from 'react'; import styled from 'styled-components'; -import { isEmpty } from 'lodash'; import { TypedLensByValueInput } from '../../../../../lens/public'; import { useSeriesStorage } from './hooks/use_series_storage'; import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { ReportViewType, SeriesUrl } from './types'; -import { ReportTypes } from './configurations/constants'; +import { useExpViewTimeRange } from './hooks/use_time_range'; interface Props { lensAttributes: TypedLensByValueInput['attributes']; setLastUpdated: Dispatch>; } -export const combineTimeRanges = ( - reportType: ReportViewType, - allSeries: SeriesUrl[], - firstSeries?: SeriesUrl -) => { - let to: string = ''; - let from: string = ''; - - if (reportType === ReportTypes.KPI) { - return firstSeries?.time; - } - - allSeries.forEach((series) => { - if ( - series.dataType && - series.selectedMetricField && - !isEmpty(series.reportDefinitions) && - series.time - ) { - const seriesTo = new Date(series.time.to); - const seriesFrom = new Date(series.time.from); - if (!to || seriesTo > new Date(to)) { - to = series.time.to; - } - if (!from || seriesFrom < new Date(from)) { - from = series.time.from; - } - } - }); - - return { to, from }; -}; export function LensEmbeddable(props: Props) { const { lensAttributes, setLastUpdated } = props; @@ -62,11 +28,11 @@ export function LensEmbeddable(props: Props) { const LensComponent = lens?.EmbeddableComponent; - const { firstSeries, setSeries, allSeries, reportType } = useSeriesStorage(); + const { firstSeries, setSeries, reportType } = useSeriesStorage(); const firstSeriesId = 0; - const timeRange = firstSeries ? combineTimeRanges(reportType, allSeries, firstSeries) : null; + const timeRange = useExpViewTimeRange(); const onLensLoad = useCallback(() => { setLastUpdated(Date.now()); @@ -93,7 +59,7 @@ export function LensEmbeddable(props: Props) { [reportType, setSeries, firstSeries, notifications?.toasts] ); - if (timeRange === null || !firstSeries) { + if (!timeRange || !firstSeries) { return null; } From ff1b014c7bdcd2ab5aee896bca0cc077736aec58 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 12 Oct 2021 16:36:18 +0200 Subject: [PATCH 55/73] Update dependency @elastic/charts to v37 (master) (#113968) --- api_docs/charts.json | 4 +-- package.json | 2 +- .../static/utils/transform_click_event.ts | 4 +-- .../apps/main/components/chart/histogram.tsx | 7 +++-- .../vis_types/pie/public/utils/get_layers.ts | 1 - .../components/timelion_vis_component.tsx | 2 ++ .../timelion/public/helpers/panel_utils.ts | 6 ++-- .../xy/public/components/xy_settings.tsx | 1 - .../vis_types/xy/public/config/get_axis.ts | 16 ++--------- .../vis_types/xy/public/utils/domain.ts | 12 ++++---- .../utils/render_all_series.test.mocks.ts | 15 ++++++++-- .../vis_types/xy/public/vis_component.tsx | 6 +++- .../apps/dashboard/dashboard_state.ts | 14 ++++------ .../page_objects/visualize_chart_page.ts | 12 ++++---- .../services/visualizations/pie_chart.ts | 20 +++++++++++-- .../alerting/chart_preview/index.tsx | 2 +- .../RumDashboard/Charts/PageLoadDistChart.tsx | 5 ++-- .../distribution/index.tsx | 12 ++++---- .../transaction_details_tabs.tsx | 4 +-- .../app/transaction_details/types.ts | 4 +-- .../shared/charts/breakdown_chart/index.tsx | 5 +++- .../components/shared/charts/helper/helper.ts | 4 +-- .../shared/charts/timeseries_chart.tsx | 5 +++- .../document_count_chart.tsx | 9 ++++-- .../heatmap_visualization/chart_component.tsx | 3 +- .../pie_visualization/render_function.tsx | 1 - .../__snapshots__/expression.test.tsx.snap | 28 +++++++++---------- .../xy_visualization/expression.test.tsx | 16 +++++++---- .../public/xy_visualization/expression.tsx | 25 +++++++++-------- .../lens/public/xy_visualization/x_domain.tsx | 6 ++-- .../create_calendar.tsx | 8 +++--- .../explorer/swimlane_container.tsx | 23 ++++++++------- .../pages/components/charts/common/utils.ts | 2 +- .../event_rate_chart/event_rate_chart.tsx | 6 +--- .../components/app/section/apm/index.tsx | 12 ++++++-- .../public/components/app/section/helper.ts | 4 +-- .../components/app/section/logs/index.tsx | 12 ++++++-- .../components/app/section/uptime/index.tsx | 3 +- .../alert_types/threshold/visualization.tsx | 7 ++++- .../common/charts/duration_chart.tsx | 2 +- .../watch_visualization.tsx | 7 ++++- yarn.lock | 11 ++++---- 42 files changed, 205 insertions(+), 143 deletions(-) diff --git a/api_docs/charts.json b/api_docs/charts.json index 5d4f047a247e2..83a2a93df42a1 100644 --- a/api_docs/charts.json +++ b/api_docs/charts.json @@ -229,7 +229,7 @@ ", xAccessor: string | number | ", "AccessorFn", ") => ({ x: selectedRange }: ", - "XYBrushArea", + "XYBrushEvent", ") => ", { "pluginId": "charts", @@ -4266,4 +4266,4 @@ } ] } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 705d902d6afef..16422e3fda27e 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "@elastic/apm-generator": "link:bazel-bin/packages/elastic-apm-generator", "@elastic/apm-rum": "^5.9.1", "@elastic/apm-rum-react": "^1.3.1", - "@elastic/charts": "34.2.1", + "@elastic/charts": "37.0.0", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.21", "@elastic/ems-client": "7.15.0", diff --git a/src/plugins/charts/public/static/utils/transform_click_event.ts b/src/plugins/charts/public/static/utils/transform_click_event.ts index 7fdd59f47988d..d175046b20ebb 100644 --- a/src/plugins/charts/public/static/utils/transform_click_event.ts +++ b/src/plugins/charts/public/static/utils/transform_click_event.ts @@ -9,7 +9,7 @@ import { XYChartSeriesIdentifier, GeometryValue, - XYBrushArea, + XYBrushEvent, Accessor, AccessorFn, Datum, @@ -261,7 +261,7 @@ export const getFilterFromSeriesFn = */ export const getBrushFromChartBrushEventFn = (table: Datatable, xAccessor: Accessor | AccessorFn) => - ({ x: selectedRange }: XYBrushArea): BrushTriggerEvent => { + ({ x: selectedRange }: XYBrushEvent): BrushTriggerEvent => { const [start, end] = selectedRange ?? [0, 0]; const range: [number, number] = [start, end]; const column = table.columns.findIndex(({ id }) => validateAccessorId(id, xAccessor)); diff --git a/src/plugins/discover/public/application/apps/main/components/chart/histogram.tsx b/src/plugins/discover/public/application/apps/main/components/chart/histogram.tsx index 333050e1ca5e6..350c46591c8b4 100644 --- a/src/plugins/discover/public/application/apps/main/components/chart/histogram.tsx +++ b/src/plugins/discover/public/application/apps/main/components/chart/histogram.tsx @@ -14,6 +14,7 @@ import dateMath from '@elastic/datemath'; import { Axis, BrushEndListener, + XYBrushEvent, Chart, ElementClickListener, HistogramBarSeries, @@ -65,8 +66,8 @@ export function DiscoverHistogram({ const timeZone = getTimezone(uiSettings); const { chartData, fetchStatus } = dataState; - const onBrushEnd: BrushEndListener = useCallback( - ({ x }) => { + const onBrushEnd = useCallback( + ({ x }: XYBrushEvent) => { if (!x) { return; } @@ -184,7 +185,7 @@ export function DiscoverHistogram({ { const fillLabel: Partial = { - textInvertible: true, valueFont: { fontWeight: 700, }, diff --git a/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx b/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx index d7b7bb14723d7..e6d2638bedf48 100644 --- a/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx +++ b/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx @@ -64,6 +64,8 @@ const DefaultYAxis = () => ( id="left" domain={withStaticPadding({ fit: false, + min: NaN, + max: NaN, })} position={Position.Left} groupId={`${MAIN_GROUP_ID}`} diff --git a/src/plugins/vis_types/timelion/public/helpers/panel_utils.ts b/src/plugins/vis_types/timelion/public/helpers/panel_utils.ts index 3c76b95bd05ca..98be5efc55a26 100644 --- a/src/plugins/vis_types/timelion/public/helpers/panel_utils.ts +++ b/src/plugins/vis_types/timelion/public/helpers/panel_utils.ts @@ -88,8 +88,8 @@ const adaptYaxisParams = (yaxis: IAxis) => { tickFormat: y.tickFormatter, domain: withStaticPadding({ fit: y.min === undefined && y.max === undefined, - min: y.min, - max: y.max, + min: y.min ?? NaN, + max: y.max ?? NaN, }), }; }; @@ -118,6 +118,8 @@ export const extractAllYAxis = (series: Series[]) => { groupId, domain: withStaticPadding({ fit: false, + min: NaN, + max: NaN, }), id: (yaxis?.position || Position.Left) + index, position: Position.Left, diff --git a/src/plugins/vis_types/xy/public/components/xy_settings.tsx b/src/plugins/vis_types/xy/public/components/xy_settings.tsx index 5e02b65822d6c..74aff7535c2d8 100644 --- a/src/plugins/vis_types/xy/public/components/xy_settings.tsx +++ b/src/plugins/vis_types/xy/public/components/xy_settings.tsx @@ -71,7 +71,6 @@ function getValueLabelsStyling() { return { displayValue: { fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, - fill: { textInverted: false, textContrast: true }, alignment: { horizontal: HorizontalAlignment.Center, vertical: VerticalAlignment.Middle }, }, }; diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index b5cc96830e46a..09495725296cd 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { identity, isNil } from 'lodash'; +import { identity } from 'lodash'; import { AxisSpec, TickFormatter, YDomainRange, ScaleType as ECScaleType } from '@elastic/charts'; @@ -171,17 +171,5 @@ function getAxisDomain( const fit = defaultYExtents; const padding = boundsMargin || undefined; - if (!isNil(min) && !isNil(max)) { - return { fit, padding, min, max }; - } - - if (!isNil(min)) { - return { fit, padding, min }; - } - - if (!isNil(max)) { - return { fit, padding, max }; - } - - return { fit, padding }; + return { fit, padding, min: min ?? NaN, max: max ?? NaN }; } diff --git a/src/plugins/vis_types/xy/public/utils/domain.ts b/src/plugins/vis_types/xy/public/utils/domain.ts index fa8dd74e3942a..5b1310863979a 100644 --- a/src/plugins/vis_types/xy/public/utils/domain.ts +++ b/src/plugins/vis_types/xy/public/utils/domain.ts @@ -33,6 +33,8 @@ export const getXDomain = (params: Aspect['params']): DomainRange => { return { minInterval, + min: NaN, + max: NaN, }; }; @@ -74,9 +76,9 @@ export const getAdjustedDomain = ( }; } - return 'interval' in params - ? { - minInterval: params.interval, - } - : {}; + return { + minInterval: 'interval' in params ? params.interval : undefined, + min: NaN, + max: NaN, + }; }; diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts index 5fe1b03dd8b93..c14e313b1e7a4 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts @@ -112,7 +112,10 @@ export const getVisConfig = (): VisConfig => { mode: AxisMode.Normal, type: 'linear', }, - domain: {}, + domain: { + min: NaN, + max: NaN, + }, integersOnly: false, }, ], @@ -246,7 +249,10 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { mode: AxisMode.Normal, type: 'linear', }, - domain: {}, + domain: { + min: NaN, + max: NaN, + }, integersOnly: false, }, ], @@ -435,7 +441,10 @@ export const getVisConfigPercentiles = (): VisConfig => { mode: AxisMode.Normal, type: 'linear', }, - domain: {}, + domain: { + min: NaN, + max: NaN, + }, integersOnly: false, }, ], diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index f4d566f49602e..515ad3e7eaf6f 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -19,6 +19,7 @@ import { ScaleType, AccessorFn, Accessor, + XYBrushEvent, } from '@elastic/charts'; import { compact } from 'lodash'; @@ -131,7 +132,10 @@ const VisComponent = (props: VisComponentProps) => { ): BrushEndListener | undefined => { if (xAccessor !== null && isInterval) { return (brushArea) => { - const event = getBrushFromChartBrushEventFn(visData, xAccessor)(brushArea); + const event = getBrushFromChartBrushEventFn( + visData, + xAccessor + )(brushArea as XYBrushEvent); props.fireEvent(event); }; } diff --git a/test/functional/apps/dashboard/dashboard_state.ts b/test/functional/apps/dashboard/dashboard_state.ts index 45ba62749dd77..0cc0fa4806482 100644 --- a/test/functional/apps/dashboard/dashboard_state.ts +++ b/test/functional/apps/dashboard/dashboard_state.ts @@ -7,6 +7,7 @@ */ import expect from '@kbn/expect'; +import chroma from 'chroma-js'; import { PIE_CHART_VIS_NAME, AREA_CHART_VIS_NAME } from '../../page_objects/dashboard_page'; import { DEFAULT_PANEL_WIDTH } from '../../../../src/plugins/dashboard/public/application/embeddable/dashboard_constants'; @@ -264,14 +265,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async () => { - const allPieSlicesColor = await pieChart.getAllPieSliceStyles('80,000'); - let whitePieSliceCounts = 0; - allPieSlicesColor.forEach((style) => { - if (style.indexOf('rgb(255, 255, 255)') > -1) { - whitePieSliceCounts++; - } - }); - + const allPieSlicesColor = await pieChart.getAllPieSliceColor('80,000'); + const whitePieSliceCounts = allPieSlicesColor.reduce((count, color) => { + // converting the color to a common format, testing the color, not the string format + return chroma(color).hex().toUpperCase() === '#FFFFFF' ? count + 1 : count; + }, 0); expect(whitePieSliceCounts).to.be(1); }); }); diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts index d2e4091f93577..b0e9e21d07b0b 100644 --- a/test/functional/page_objects/visualize_chart_page.ts +++ b/test/functional/page_objects/visualize_chart_page.ts @@ -7,7 +7,7 @@ */ import { Position } from '@elastic/charts'; -import Color from 'color'; +import chroma from 'chroma-js'; import { FtrService } from '../ftr_provider_context'; @@ -181,17 +181,17 @@ export class VisualizeChartPageObject extends FtrService { return items.some(({ color: c }) => c === color); } - public async doesSelectedLegendColorExistForPie(color: string) { + public async doesSelectedLegendColorExistForPie(matchingColor: string) { if (await this.isNewLibraryChart(pieChartSelector)) { + const hexMatchingColor = chroma(matchingColor).hex().toUpperCase(); const slices = (await this.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ?? []; - return slices.some(({ color: c }) => { - const rgbColor = new Color(color).rgb().toString(); - return c === rgbColor; + return slices.some(({ color }) => { + return hexMatchingColor === chroma(color).hex().toUpperCase(); }); } - return await this.testSubjects.exists(`legendSelectedColor-${color}`); + return await this.testSubjects.exists(`legendSelectedColor-${matchingColor}`); } public async expectError() { diff --git a/test/functional/services/visualizations/pie_chart.ts b/test/functional/services/visualizations/pie_chart.ts index 7c925318f0211..ff0c24e2830cf 100644 --- a/test/functional/services/visualizations/pie_chart.ts +++ b/test/functional/services/visualizations/pie_chart.ts @@ -7,6 +7,7 @@ */ import expect from '@kbn/expect'; +import { isNil } from 'lodash'; import { FtrService } from '../../ftr_provider_context'; const pieChartSelector = 'visTypePieChart'; @@ -100,8 +101,8 @@ export class PieChartService extends FtrService { return await pieSlice.getAttribute('style'); } - async getAllPieSliceStyles(name: string) { - this.log.debug(`VisualizePage.getAllPieSliceStyles(${name})`); + async getAllPieSliceColor(name: string) { + this.log.debug(`VisualizePage.getAllPieSliceColor(${name})`); if (await this.visChart.isNewLibraryChart(pieChartSelector)) { const slices = (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ?? @@ -112,9 +113,22 @@ export class PieChartService extends FtrService { return selectedSlice.map((slice) => slice.color); } const pieSlices = await this.getAllPieSlices(name); - return await Promise.all( + const slicesStyles = await Promise.all( pieSlices.map(async (pieSlice) => await pieSlice.getAttribute('style')) ); + return slicesStyles + .map( + (styles) => + styles.split(';').reduce>((styleAsObj, style) => { + const stylePair = style.split(':'); + if (stylePair.length !== 2) { + return styleAsObj; + } + styleAsObj[stylePair[0].trim()] = stylePair[1].trim(); + return styleAsObj; + }, {}).fill // in vislib the color is available on the `fill` style prop + ) + .filter((d) => !isNil(d)); } async getPieChartData() { diff --git a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx b/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx index 8a54c76df0f69..ee6a58b0dbb76 100644 --- a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx @@ -96,7 +96,7 @@ export function ChartPreview({ position={Position.Left} tickFormat={yTickFormat} ticks={5} - domain={{ max: yMax }} + domain={{ max: yMax, min: NaN }} /> { + const onBrushEnd = ({ x }: XYBrushEvent) => { if (!x) { return; } @@ -99,7 +100,7 @@ export function PageLoadDistChart({ diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index 97f38a8123a4e..efd01c32b2462 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -6,7 +6,7 @@ */ import React, { useEffect } from 'react'; -import { BrushEndListener, XYBrushArea } from '@elastic/charts'; +import { BrushEndListener, XYBrushEvent } from '@elastic/charts'; import { EuiBadge, EuiFlexGroup, @@ -61,7 +61,7 @@ export function getFormattedSelection(selection: Selection): string { } interface TransactionDistributionProps { - onChartSelection: BrushEndListener; + onChartSelection: (event: XYBrushEvent) => void; onClearSelection: () => void; selection?: Selection; traceSamples: TabContentProps['traceSamples']; @@ -126,10 +126,8 @@ export function TransactionDistribution({ const trackApmEvent = useUiTracker({ app: 'apm' }); - const onTrackedChartSelection: BrushEndListener = ( - brushArea: XYBrushArea - ) => { - onChartSelection(brushArea); + const onTrackedChartSelection = (brushEvent: XYBrushEvent) => { + onChartSelection(brushEvent); trackApmEvent({ metric: 'transaction_distribution_chart_selection' }); }; @@ -216,7 +214,7 @@ export function TransactionDistribution({ markerCurrentTransaction={markerCurrentTransaction} markerPercentile={DEFAULT_PERCENTILE_THRESHOLD} markerValue={response.percentileThresholdValue ?? 0} - onChartSelection={onTrackedChartSelection} + onChartSelection={onTrackedChartSelection as BrushEndListener} hasData={hasData} selection={selection} status={status} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/transaction_details_tabs.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/transaction_details_tabs.tsx index b249161980586..9ccca9886e679 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/transaction_details_tabs.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/transaction_details_tabs.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { omit } from 'lodash'; import { useHistory } from 'react-router-dom'; -import { XYBrushArea } from '@elastic/charts'; +import { XYBrushEvent } from '@elastic/charts'; import { EuiPanel, EuiSpacer, EuiTabs, EuiTab } from '@elastic/eui'; import { useUrlParams } from '../../../context/url_params_context/use_url_params'; @@ -48,7 +48,7 @@ export function TransactionDetailsTabs() { environment, }); - const selectSampleFromChartSelection = (selection: XYBrushArea) => { + const selectSampleFromChartSelection = (selection: XYBrushEvent) => { if (selection !== undefined) { const { x } = selection; if (Array.isArray(x)) { diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/types.ts b/x-pack/plugins/apm/public/components/app/transaction_details/types.ts index 1ccb3d01a9b28..c3d2b9648e82a 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/types.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { XYBrushArea } from '@elastic/charts'; +import { XYBrushEvent } from '@elastic/charts'; import type { TraceSample } from '../../../hooks/use_transaction_trace_samples_fetcher'; @@ -14,6 +14,6 @@ export interface TabContentProps { onFilter: () => void; sampleRangeFrom?: number; sampleRangeTo?: number; - selectSampleFromChartSelection: (selection: XYBrushArea) => void; + selectSampleFromChartSelection: (selection: XYBrushEvent) => void; traceSamples: TraceSample[]; } diff --git a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx index 213bac40c2248..16157071affcd 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/breakdown_chart/index.tsx @@ -17,6 +17,7 @@ import { ScaleType, Settings, TickFormatter, + XYBrushEvent, } from '@elastic/charts'; import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -96,7 +97,9 @@ export function BreakdownChart({ onBrushEnd({ x, history })} + onBrushEnd={(event) => + onBrushEnd({ x: (event as XYBrushEvent).x, history }) + } showLegend showLegendExtra legendPosition={Position.Bottom} diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/helper.ts b/x-pack/plugins/apm/public/components/shared/charts/helper/helper.ts index d94f2ce8f5c5d..9dccddd509387 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/helper.ts +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/helper.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { XYBrushArea } from '@elastic/charts'; +import { XYBrushEvent } from '@elastic/charts'; import { History } from 'history'; import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; import { fromQuery, toQuery } from '../../Links/url_helpers'; @@ -14,7 +14,7 @@ export const onBrushEnd = ({ x, history, }: { - x: XYBrushArea['x']; + x: XYBrushEvent['x']; history: History; }) => { if (x) { diff --git a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx index 65ecdec0f36a5..08e8908d50e7a 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx @@ -20,6 +20,7 @@ import { ScaleType, Settings, YDomainRange, + XYBrushEvent, } from '@elastic/charts'; import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -115,7 +116,9 @@ export function TimeseriesChart({ onBrushEnd({ x, history })} + onBrushEnd={(event) => + onBrushEnd({ x: (event as XYBrushEvent).x, history }) + } theme={{ ...chartTheme, areaSeriesStyle: { diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/document_count_content/document_count_chart/document_count_chart.tsx b/x-pack/plugins/data_visualizer/public/application/common/components/document_count_content/document_count_chart/document_count_chart.tsx index b8df4defa18a2..6459fc4006cea 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/document_count_content/document_count_chart/document_count_chart.tsx +++ b/x-pack/plugins/data_visualizer/public/application/common/components/document_count_content/document_count_chart/document_count_chart.tsx @@ -20,6 +20,7 @@ import { ScaleType, Settings, XYChartElementEvent, + XYBrushEvent, } from '@elastic/charts'; import moment from 'moment'; import { useDataVisualizerKibana } from '../../../../kibana_context'; @@ -91,7 +92,7 @@ export const DocumentCountChart: FC = ({ [data] ); - const onBrushEnd: BrushEndListener = ({ x }) => { + const onBrushEnd = ({ x }: XYBrushEvent) => { if (!x) { return; } @@ -117,7 +118,11 @@ export const DocumentCountChart: FC = ({ height: 120, }} > - + = ({ }; const config: HeatmapSpec['config'] = { - onBrushEnd, grid: { stroke: { width: @@ -338,6 +338,7 @@ export const HeatmapComponent: FC = ({ labelOptions: { maxLines: args.legend.shouldTruncate ? args.legend?.maxLines ?? 1 : 0 }, }, }} + onBrushEnd={onBrushEnd as BrushEndListener} /> = { - textInvertible: true, valueFont: { fontWeight: 700, }, diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap index fe3137c905ffb..0fad522624975 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap @@ -73,8 +73,8 @@ exports[`xy_expression XYChart component it renders area 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -302,8 +302,8 @@ exports[`xy_expression XYChart component it renders bar 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -545,8 +545,8 @@ exports[`xy_expression XYChart component it renders horizontal bar 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -788,8 +788,8 @@ exports[`xy_expression XYChart component it renders line 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -1017,8 +1017,8 @@ exports[`xy_expression XYChart component it renders stacked area 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -1254,8 +1254,8 @@ exports[`xy_expression XYChart component it renders stacked bar 1`] = ` domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ @@ -1505,8 +1505,8 @@ exports[`xy_expression XYChart component it renders stacked horizontal bar 1`] = domain={ Object { "fit": false, - "max": undefined, - "min": undefined, + "max": NaN, + "min": NaN, } } gridLine={ diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 4056aa730c2ab..af2995fb65b71 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -809,8 +809,8 @@ describe('xy_expression', () => { ); expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({ fit: true, - min: undefined, - max: undefined, + min: NaN, + max: NaN, }); }); @@ -838,6 +838,8 @@ describe('xy_expression', () => { ); expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({ fit: false, + min: NaN, + max: NaN, }); }); @@ -867,8 +869,8 @@ describe('xy_expression', () => { ); expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({ fit: false, - min: undefined, - max: undefined, + min: NaN, + max: NaN, }); }); @@ -959,7 +961,11 @@ describe('xy_expression', () => { }} /> ); - expect(component.find(Settings).prop('xDomain')).toEqual({ minInterval: 101 }); + expect(component.find(Settings).prop('xDomain')).toEqual({ + minInterval: 101, + min: NaN, + max: NaN, + }); }); test('disabled legend extra by default', () => { diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 5dfad58f50018..87462e71f3cf6 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -25,9 +25,12 @@ import { LayoutDirection, ElementClickListener, BrushEndListener, + XYBrushEvent, CurveType, LegendPositionConfig, LabelOverflowConstraint, + DisplayValueStyle, + RecursivePartial, } from '@elastic/charts'; import { I18nProvider } from '@kbn/i18n/react'; import type { @@ -169,7 +172,9 @@ export const getXyChartRenderer = (dependencies: { }, }); -function getValueLabelsStyling(isHorizontal: boolean) { +function getValueLabelsStyling(isHorizontal: boolean): { + displayValue: RecursivePartial; +} { const VALUE_LABELS_MAX_FONTSIZE = 12; const VALUE_LABELS_MIN_FONTSIZE = 10; const VALUE_LABELS_VERTICAL_OFFSET = -10; @@ -178,11 +183,9 @@ function getValueLabelsStyling(isHorizontal: boolean) { return { displayValue: { fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, - fill: { textContrast: true, textInverted: false, textBorder: 0 }, + fill: { textBorder: 0 }, alignment: isHorizontal - ? { - vertical: VerticalAlignment.Middle, - } + ? { vertical: VerticalAlignment.Middle } : { horizontal: HorizontalAlignment.Center }, offsetX: isHorizontal ? VALUE_LABELS_HORIZONTAL_OFFSET : 0, offsetY: isHorizontal ? 0 : VALUE_LABELS_VERTICAL_OFFSET, @@ -388,14 +391,14 @@ export function XYChart({ }) ); const fit = !hasBarOrArea && extent.mode === 'dataBounds'; - let min: undefined | number; - let max: undefined | number; + let min: number = NaN; + let max: number = NaN; if (extent.mode === 'custom') { const { inclusiveZeroError, boundaryError } = validateExtent(hasBarOrArea, extent); if (!inclusiveZeroError && !boundaryError) { - min = extent.lowerBound; - max = extent.upperBound; + min = extent.lowerBound ?? NaN; + max = extent.upperBound ?? NaN; } } else { const axisHasThreshold = thresholdLayers.some(({ yConfig }) => @@ -517,7 +520,7 @@ export function XYChart({ onClickValue(context); }; - const brushHandler: BrushEndListener = ({ x }) => { + const brushHandler = ({ x }: XYBrushEvent) => { if (!x) { return; } @@ -592,7 +595,7 @@ export function XYChart({ allowBrushingLastHistogramBucket={Boolean(isTimeViz)} rotation={shouldRotate ? 90 : 0} xDomain={xDomain} - onBrushEnd={interactive ? brushHandler : undefined} + onBrushEnd={interactive ? (brushHandler as BrushEndListener) : undefined} onElementClick={interactive ? clickHandler : undefined} legendAction={getLegendAction( filteredLayers, diff --git a/x-pack/plugins/lens/public/xy_visualization/x_domain.tsx b/x-pack/plugins/lens/public/xy_visualization/x_domain.tsx index ccb047d54e369..d5eb8ac1e92ba 100644 --- a/x-pack/plugins/lens/public/xy_visualization/x_domain.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/x_domain.tsx @@ -26,12 +26,12 @@ export const getXDomain = ( ) => { const baseDomain = isTimeViz ? { - min: data.dateRange?.fromDate.getTime(), - max: data.dateRange?.toDate.getTime(), + min: data.dateRange?.fromDate.getTime() ?? NaN, + max: data.dateRange?.toDate.getTime() ?? NaN, minInterval, } : isHistogram - ? { minInterval } + ? { minInterval, min: NaN, max: NaN } : undefined; if (isHistogram && isFullyQualified(baseDomain)) { diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx index b4015d0c0eb92..1fae57c7922ce 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx @@ -9,7 +9,7 @@ import React, { FC, Fragment, useCallback, memo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import moment from 'moment'; -import { XYBrushArea } from '@elastic/charts'; +import { XYBrushEvent, BrushEndListener } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, @@ -57,7 +57,7 @@ export const CreateCalendar: FC = ({ const { euiTheme } = useCurrentEuiTheme(); const onBrushEnd = useCallback( - ({ x }: XYBrushArea) => { + ({ x }: XYBrushEvent) => { if (x && x.length === 2) { const end = x[1] < minSelectableTimeStamp ? null : x[1]; if (end !== null) { @@ -252,7 +252,7 @@ interface ChartProps { eventRateData: LineChartPoint[]; anomalies: Anomaly[]; loading: boolean; - onBrushEnd(area: XYBrushArea): void; + onBrushEnd(area: XYBrushEvent): void; overlayRanges: Array<{ start: number; end: number }>; overlayColor: string; } @@ -272,7 +272,7 @@ const Chart: FC = memo( color: overlayColor, showMarker: false, }))} - onBrushEnd={onBrushEnd} + onBrushEnd={onBrushEnd as BrushEndListener} /> ), (prev: ChartProps, next: ChartProps) => { diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index 49bd00d888cf8..ef8e80381293e 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -18,6 +18,7 @@ import { import { throttle } from 'lodash'; import { Chart, + BrushEndListener, Settings, Heatmap, HeatmapElementEvent, @@ -286,16 +287,6 @@ export const SwimlaneContainer: FC = ({ if (!showSwimlane) return {}; const config: HeatmapSpec['config'] = { - onBrushEnd: (e: HeatmapBrushEvent) => { - if (!e.cells.length) return; - - onCellsSelection({ - lanes: e.y as string[], - times: e.x.map((v) => (v as number) / 1000) as [number, number], - type: swimlaneType, - viewByFieldName: swimlaneData.fieldName, - }); - }, grid: { cellHeight: { min: CELL_HEIGHT, @@ -396,6 +387,17 @@ export const SwimlaneContainer: FC = ({ [swimlaneData] ); + const onBrushEnd = (e: HeatmapBrushEvent) => { + if (!e.cells.length) return; + + onCellsSelection({ + lanes: e.y as string[], + times: e.x!.map((v) => (v as number) / 1000) as [number, number], + type: swimlaneType, + viewByFieldName: swimlaneData.fieldName, + }); + }; + // A resize observer is required to compute the bucket span based on the chart width to fetch the data accordingly return ( @@ -427,6 +429,7 @@ export const SwimlaneContainer: FC = ({ xDomain={xDomain} tooltip={tooltipOptions} debugState={window._echDebugStateFlag ?? false} + onBrushEnd={onBrushEnd as BrushEndListener} /> = ({ {showAxis === true && } - {onBrushEnd === undefined ? ( - - ) : ( - - )} + {overlayRanges && overlayRanges.map((range, i) => ( diff --git a/x-pack/plugins/observability/public/components/app/section/apm/index.tsx b/x-pack/plugins/observability/public/components/app/section/apm/index.tsx index 7a42e96c3823d..8df14129623f6 100644 --- a/x-pack/plugins/observability/public/components/app/section/apm/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/apm/index.tsx @@ -5,7 +5,15 @@ * 2.0. */ -import { Axis, BarSeries, niceTimeFormatter, Position, ScaleType, Settings } from '@elastic/charts'; +import { + Axis, + BarSeries, + niceTimeFormatter, + Position, + ScaleType, + Settings, + XYBrushEvent, +} from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; @@ -117,7 +125,7 @@ export function APMSection({ bucketSize }: Props) { onBrushEnd({ x, history })} + onBrushEnd={(event) => onBrushEnd({ x: (event as XYBrushEvent).x, history })} theme={chartTheme} showLegend={false} xDomain={{ min, max }} diff --git a/x-pack/plugins/observability/public/components/app/section/helper.ts b/x-pack/plugins/observability/public/components/app/section/helper.ts index f1b2992386063..077bd67a8590c 100644 --- a/x-pack/plugins/observability/public/components/app/section/helper.ts +++ b/x-pack/plugins/observability/public/components/app/section/helper.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { XYBrushArea } from '@elastic/charts'; +import { XYBrushEvent } from '@elastic/charts'; import { History } from 'history'; import { fromQuery, toQuery } from '../../../utils/url'; -export const onBrushEnd = ({ x, history }: { x: XYBrushArea['x']; history: History }) => { +export const onBrushEnd = ({ x, history }: { x: XYBrushEvent['x']; history: History }) => { if (x) { const start = x[0]; const end = x[1]; diff --git a/x-pack/plugins/observability/public/components/app/section/logs/index.tsx b/x-pack/plugins/observability/public/components/app/section/logs/index.tsx index da5a8f25045a5..dcd51a531a73d 100644 --- a/x-pack/plugins/observability/public/components/app/section/logs/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/logs/index.tsx @@ -5,7 +5,15 @@ * 2.0. */ -import { Axis, BarSeries, niceTimeFormatter, Position, ScaleType, Settings } from '@elastic/charts'; +import { + Axis, + BarSeries, + niceTimeFormatter, + Position, + ScaleType, + Settings, + XYBrushEvent, +} from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, euiPaletteColorBlind, EuiSpacer, EuiTitle } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; @@ -124,7 +132,7 @@ export function LogsSection({ bucketSize }: Props) { onBrushEnd({ x, history })} + onBrushEnd={(event) => onBrushEnd({ x: (event as XYBrushEvent).x, history })} theme={chartTheme} showLegend legendPosition={Position.Right} diff --git a/x-pack/plugins/observability/public/components/app/section/uptime/index.tsx b/x-pack/plugins/observability/public/components/app/section/uptime/index.tsx index 28cbd12663c1b..8c0f1f8db7c1a 100644 --- a/x-pack/plugins/observability/public/components/app/section/uptime/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/uptime/index.tsx @@ -13,6 +13,7 @@ import { ScaleType, Settings, TickFormatter, + XYBrushEvent, } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import numeral from '@elastic/numeral'; @@ -123,7 +124,7 @@ export function UptimeSection({ bucketSize }: Props) { {/* Chart section */} onBrushEnd({ x, history })} + onBrushEnd={(event) => onBrushEnd({ x: (event as XYBrushEvent).x, history })} theme={chartTheme} showLegend={false} legendPosition={Position.Right} diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx index 1db09d0492e68..68141945d73fd 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx @@ -277,7 +277,12 @@ export const ThresholdVisualization: React.FunctionComponent = ({ showOverlappingTicks={true} tickFormat={dateFormatter} /> - + {alertVisualizationDataKeys.map((key: string) => { return ( getTickFormat(d)} diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx index 468e9dfa68e1b..c995e4a449867 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx @@ -227,7 +227,12 @@ export const WatchVisualization = () => { showOverlappingTicks={true} tickFormat={dateFormatter} /> - + {watchVisualizationDataKeys.map((key: string) => { return ( Date: Tue, 12 Oct 2021 16:36:38 +0200 Subject: [PATCH 56/73] [Fleet] Fix agent count in update modal (#114622) --- .../screens/detail/settings/update_button.tsx | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx index 8cdb3ece30621..48569d782a70b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx @@ -18,12 +18,12 @@ import { EuiConfirmModal, EuiSpacer, } from '@elastic/eui'; -import { sumBy } from 'lodash'; import type { GetAgentPoliciesResponse, PackageInfo, UpgradePackagePolicyDryRunResponse, + PackagePolicy, } from '../../../../../types'; import { InstallStatus } from '../../../../../types'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; @@ -109,10 +109,24 @@ export const UpdateButton: React.FunctionComponent = ({ }, [packagePolicyIds]); const packagePolicyCount = useMemo(() => packagePolicyIds.length, [packagePolicyIds]); + + function isStringArray(arr: unknown | string[]): arr is string[] { + return Array.isArray(arr) && arr.every((p) => typeof p === 'string'); + } + const agentCount = useMemo( - () => sumBy(agentPolicyData?.items, ({ agents }) => agents ?? 0), - [agentPolicyData] + () => + agentPolicyData?.items.reduce((acc, item) => { + const existingPolicies = isStringArray(item?.package_policies) + ? (item?.package_policies as string[]).filter((p) => packagePolicyIds.includes(p)) + : (item?.package_policies as PackagePolicy[]).filter((p) => + packagePolicyIds.includes(p.id) + ); + return (acc += existingPolicies.length > 0 && item?.agents ? item?.agents : 0); + }, 0), + [agentPolicyData, packagePolicyIds] ); + const conflictCount = useMemo( () => dryRunData?.filter((item) => item.hasErrors).length, [dryRunData] From 0b46bb1b93e01137e0c9cd957fa197ae024d7ea0 Mon Sep 17 00:00:00 2001 From: Davis Plumlee <56367316+dplumlee@users.noreply.github.com> Date: Tue, 12 Oct 2021 09:40:54 -0500 Subject: [PATCH 57/73] [Security Solution][Detection Alerts] Fixes follow-up alert refresh bugs (#112169) --- .../detection_alerts/acknowledged.spec.ts | 11 +- .../detection_alerts/closing.spec.ts | 69 +- .../detection_alerts/opening.spec.ts | 15 +- .../cypress/screens/alerts.ts | 6 + .../timeline_actions/alert_context_menu.tsx | 7 +- .../components/take_action_dropdown/index.tsx | 43 +- .../__snapshots__/index.test.tsx.snap | 788 +++++++++--------- .../side_panel/event_details/footer.tsx | 46 +- .../public/container/use_update_alerts.ts | 8 +- .../hooks/use_status_bulk_action_items.tsx | 2 +- 10 files changed, 549 insertions(+), 446 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/acknowledged.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/acknowledged.spec.ts index 5d72105178b69..2dad11ac7e937 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/acknowledged.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/acknowledged.spec.ts @@ -6,7 +6,11 @@ */ import { getNewRule } from '../../objects/rule'; -import { ALERTS_COUNT, TAKE_ACTION_POPOVER_BTN } from '../../screens/alerts'; +import { + ALERTS_COUNT, + TAKE_ACTION_POPOVER_BTN, + ALERT_COUNT_TABLE_FIRST_ROW_COUNT, +} from '../../screens/alerts'; import { selectNumberOfAlerts, @@ -50,11 +54,16 @@ describe('Marking alerts as acknowledged', () => { markAcknowledgedFirstAlert(); const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should('have.text', `${expectedNumberOfAlerts}`); goToAcknowledgedAlerts(); waitForAlerts(); cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlertsToBeMarkedAcknowledged} alert`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${numberOfAlertsToBeMarkedAcknowledged}` + ); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/closing.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/closing.spec.ts index 602619b056244..860a4e6089a27 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/closing.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/closing.spec.ts @@ -6,7 +6,13 @@ */ import { getNewRule } from '../../objects/rule'; -import { ALERTS_COUNT, SELECTED_ALERTS, TAKE_ACTION_POPOVER_BTN } from '../../screens/alerts'; +import { + ALERTS_COUNT, + SELECTED_ALERTS, + TAKE_ACTION_POPOVER_BTN, + ALERT_COUNT_TABLE_FIRST_ROW_COUNT, + ALERTS_TREND_SIGNAL_RULE_NAME_PANEL, +} from '../../screens/alerts'; import { closeFirstAlert, @@ -46,6 +52,7 @@ describe('Closing alerts', () => { .then((alertNumberString) => { const numberOfAlerts = alertNumberString.split(' ')[0]; cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should('have.text', `${numberOfAlerts}`); selectNumberOfAlerts(numberOfAlertsToBeClosed); @@ -56,6 +63,10 @@ describe('Closing alerts', () => { const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlertsAfterClosing} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${expectedNumberOfAlertsAfterClosing}` + ); goToClosedAlerts(); waitForAlerts(); @@ -75,6 +86,10 @@ describe('Closing alerts', () => { 'have.text', `${expectedNumberOfClosedAlertsAfterOpened} alerts` ); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${expectedNumberOfClosedAlertsAfterOpened}` + ); goToOpenedAlerts(); waitForAlerts(); @@ -83,6 +98,10 @@ describe('Closing alerts', () => { +numberOfAlerts - expectedNumberOfClosedAlertsAfterOpened; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfOpenedAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${expectedNumberOfOpenedAlerts}` + ); }); }); @@ -103,11 +122,59 @@ describe('Closing alerts', () => { const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeClosed; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should('have.text', `${expectedNumberOfAlerts}`); + + goToClosedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlertsToBeClosed} alert`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${numberOfAlertsToBeClosed}` + ); + }); + }); + + it('Updates trend histogram whenever alert status is updated in table', () => { + const numberOfAlertsToBeClosed = 1; + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should('have.text', `${numberOfAlerts}`); + + selectNumberOfAlerts(numberOfAlertsToBeClosed); + + cy.get(SELECTED_ALERTS).should('have.text', `Selected ${numberOfAlertsToBeClosed} alert`); + + closeAlerts(); + waitForAlerts(); + + const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed; + cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlertsAfterClosing} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${expectedNumberOfAlertsAfterClosing}` + ); goToClosedAlerts(); waitForAlerts(); cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlertsToBeClosed} alert`); + + const numberOfAlertsToBeOpened = 1; + selectNumberOfAlerts(numberOfAlertsToBeOpened); + + cy.get(SELECTED_ALERTS).should('have.text', `Selected ${numberOfAlertsToBeOpened} alert`); + cy.get(ALERTS_TREND_SIGNAL_RULE_NAME_PANEL).should('exist'); + + openAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).should('not.exist'); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should('not.exist'); + cy.get(ALERTS_TREND_SIGNAL_RULE_NAME_PANEL).should('not.exist'); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/opening.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/opening.spec.ts index 645abfed8ac0e..87cef27b5b346 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/opening.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/opening.spec.ts @@ -6,7 +6,12 @@ */ import { getNewRule } from '../../objects/rule'; -import { ALERTS_COUNT, SELECTED_ALERTS, TAKE_ACTION_POPOVER_BTN } from '../../screens/alerts'; +import { + ALERTS_COUNT, + SELECTED_ALERTS, + TAKE_ACTION_POPOVER_BTN, + ALERT_COUNT_TABLE_FIRST_ROW_COUNT, +} from '../../screens/alerts'; import { closeAlerts, @@ -74,6 +79,10 @@ describe('Opening alerts', () => { const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeOpened; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${expectedNumberOfAlerts}` + ); goToOpenedAlerts(); waitForAlerts(); @@ -82,6 +91,10 @@ describe('Opening alerts', () => { 'have.text', `${numberOfOpenedAlerts + numberOfAlertsToBeOpened} alerts`.toString() ); + cy.get(ALERT_COUNT_TABLE_FIRST_ROW_COUNT).should( + 'have.text', + `${numberOfOpenedAlerts + numberOfAlertsToBeOpened}` + ); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts.ts b/x-pack/plugins/security_solution/cypress/screens/alerts.ts index 675a25641a2bd..d18a8e1ba10ab 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts.ts @@ -70,3 +70,9 @@ export const TAKE_ACTION_POPOVER_BTN = '[data-test-subj="selectedShowBulkActions export const TIMELINE_CONTEXT_MENU_BTN = '[data-test-subj="timeline-context-menu-button"]'; export const ATTACH_ALERT_TO_CASE_BUTTON = '[data-test-subj="attach-alert-to-case-button"]'; + +export const ALERT_COUNT_TABLE_FIRST_ROW_COUNT = + '[data-test-subj="alertsCountTable"] tr:nth-child(1) td:nth-child(2) .euiTableCellContent__text'; + +export const ALERTS_TREND_SIGNAL_RULE_NAME_PANEL = + '[data-test-subj="render-content-signal.rule.name"]'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index fc8dd4b024fd9..06d61b3f0b284 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -12,6 +12,7 @@ import { indexOf } from 'lodash'; import { connect, ConnectedProps } from 'react-redux'; import { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { get } from 'lodash/fp'; +import { useRouteSpy } from '../../../../common/utils/route/use_route_spy'; import { buildGetAlertByIdQuery } from '../../../../common/components/exceptions/helpers'; import { EventsTdContent } from '../../../../timelines/components/timeline/styles'; import { DEFAULT_ICON_BUTTON_WIDTH } from '../../../../timelines/components/timeline/helpers'; @@ -63,6 +64,7 @@ const AlertContextMenuComponent: React.FC { const [isPopoverOpen, setPopover] = useState(false); + const [routeProps] = useRouteSpy(); const afterItemSelection = useCallback(() => { setPopover(false); @@ -112,10 +114,13 @@ const AlertContextMenuComponent: React.FC { if (timelineId === TimelineId.active) { refetchQuery([timelineQuery]); + if (routeProps.pageName === 'alerts') { + refetchQuery(globalQuery); + } } else { refetchQuery(globalQuery); } - }, [timelineId, globalQuery, timelineQuery]); + }, [timelineId, globalQuery, timelineQuery, routeProps]); const { exceptionModalType, diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index 200b21bbecc4b..f7d65d1a3f3f4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -9,8 +9,7 @@ import React, { useState, useCallback, useMemo } from 'react'; import { EuiContextMenuPanel, EuiButton, EuiPopover } from '@elastic/eui'; import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { isEmpty } from 'lodash/fp'; -import { connect, ConnectedProps } from 'react-redux'; -import { TimelineEventsDetailsItem, TimelineId } from '../../../../common'; +import { TimelineEventsDetailsItem } from '../../../../common'; import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations'; import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions'; import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions'; @@ -24,8 +23,6 @@ import { Status } from '../../../../common/detection_engine/schemas/common/schem import { isAlertFromEndpointAlert } from '../../../common/utils/endpoint_alert_check'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useAddToCaseActions } from '../alerts_table/timeline_actions/use_add_to_case_actions'; -import { inputsModel, inputsSelectors, State } from '../../../common/store'; - interface ActionsData { alertStatus: Status; eventId: string; @@ -48,7 +45,7 @@ export interface TakeActionDropdownProps { timelineId: string; } -export const TakeActionDropdownComponent = React.memo( +export const TakeActionDropdown = React.memo( ({ detailsData, ecsData, @@ -61,9 +58,7 @@ export const TakeActionDropdownComponent = React.memo( onAddIsolationStatusClick, refetch, timelineId, - globalQuery, - timelineQuery, - }: TakeActionDropdownProps & PropsFromRedux) => { + }: TakeActionDropdownProps) => { const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled'); const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -146,24 +141,12 @@ export const TakeActionDropdownComponent = React.memo( closePopoverHandler(); }, [closePopoverHandler]); - const refetchQuery = (newQueries: inputsModel.GlobalQuery[]) => { - newQueries.forEach((q) => q.refetch && (q.refetch as inputsModel.Refetch)()); - }; - - const refetchAll = useCallback(() => { - if (timelineId === TimelineId.active) { - refetchQuery([timelineQuery]); - } else { - refetchQuery(globalQuery); - } - }, [timelineId, globalQuery, timelineQuery]); - const { actionItems: statusActionItems } = useAlertsActions({ alertStatus: actionsData.alertStatus, closePopover: closePopoverAndFlyout, eventId: actionsData.eventId, indexName, - refetch: refetchAll, + refetch, timelineId, }); @@ -233,21 +216,3 @@ export const TakeActionDropdownComponent = React.memo( ) : null; } ); - -const makeMapStateToProps = () => { - const getGlobalQueries = inputsSelectors.globalQuery(); - const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); - const mapStateToProps = (state: State, { timelineId }: TakeActionDropdownProps) => { - return { - globalQuery: getGlobalQueries(state), - timelineQuery: getTimelineQuery(state, timelineId), - }; - }; - return mapStateToProps; -}; - -const connector = connect(makeMapStateToProps); - -type PropsFromRedux = ConnectedProps; - -export const TakeActionDropdown = connector(React.memo(TakeActionDropdownComponent)); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index 137d8d78bcdaa..2bb9da12e44ea 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -1056,7 +1056,7 @@ Array [
- - -
- + +
-
- -
- - -
-
-
- -
-
- +
+
+
+ +
+ + + , @@ -2093,7 +2095,7 @@ Array [ - - -
- -
- -
- + +
+ +
+ +
- -
-
-
-
-
-
- +
+
+
+
+
+
+
+ , ] diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx index 32c3f5a885346..4ddcd710e0406 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { EuiFlyoutFooter, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { find, get, isEmpty } from 'lodash/fp'; +import { connect, ConnectedProps } from 'react-redux'; import { TakeActionDropdown } from '../../../../detections/components/take_action_dropdown'; -import type { TimelineEventsDetailsItem } from '../../../../../common'; +import { TimelineEventsDetailsItem, TimelineId } from '../../../../../common'; import { useExceptionModal } from '../../../../detections/components/alerts_table/timeline_actions/use_add_exception_modal'; import { AddExceptionModalWrapper } from '../../../../detections/components/alerts_table/timeline_actions/alert_context_menu'; import { EventFiltersModal } from '../../../../management/pages/event_filters/view/components/modal'; @@ -18,6 +19,7 @@ import { getFieldValue } from '../../../../detections/components/host_isolation/ import { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; import { Ecs } from '../../../../../common/ecs'; import { useFetchEcsAlertsData } from '../../../../detections/containers/detection_engine/alerts/use_fetch_ecs_alerts_data'; +import { inputsModel, inputsSelectors, State } from '../../../../common/store'; interface EventDetailsFooterProps { detailsData: TimelineEventsDetailsItem[] | null; @@ -41,7 +43,7 @@ interface AddExceptionModalWrapperData { ruleName: string; } -export const EventDetailsFooter = React.memo( +export const EventDetailsFooterComponent = React.memo( ({ detailsData, expandedEvent, @@ -50,7 +52,9 @@ export const EventDetailsFooter = React.memo( loadingEventDetails, onAddIsolationStatusClick, timelineId, - }: EventDetailsFooterProps) => { + globalQuery, + timelineQuery, + }: EventDetailsFooterProps & PropsFromRedux) => { const ruleIndex = useMemo( () => find({ category: 'signal', field: 'signal.rule.index' }, detailsData)?.values, [detailsData] @@ -78,6 +82,18 @@ export const EventDetailsFooter = React.memo( [expandedEvent?.eventId] ); + const refetchQuery = (newQueries: inputsModel.GlobalQuery[]) => { + newQueries.forEach((q) => q.refetch && (q.refetch as inputsModel.Refetch)()); + }; + + const refetchAll = useCallback(() => { + if (timelineId === TimelineId.active) { + refetchQuery([timelineQuery]); + } else { + refetchQuery(globalQuery); + } + }, [timelineId, globalQuery, timelineQuery]); + const { exceptionModalType, onAddExceptionTypeClick, @@ -86,7 +102,7 @@ export const EventDetailsFooter = React.memo( ruleIndices, } = useExceptionModal({ ruleIndex, - refetch: expandedEvent?.refetch, + refetch: refetchAll, timelineId, }); const { closeAddEventFilterModal, isAddEventFilterModalOpen, onAddEventFilterClick } = @@ -113,7 +129,7 @@ export const EventDetailsFooter = React.memo( onAddEventFilterClick={onAddEventFilterClick} onAddExceptionTypeClick={onAddExceptionTypeClick} onAddIsolationStatusClick={onAddIsolationStatusClick} - refetch={expandedEvent?.refetch} + refetch={refetchAll} indexName={expandedEvent.indexName} timelineId={timelineId} /> @@ -142,3 +158,21 @@ export const EventDetailsFooter = React.memo( ); } ); + +const makeMapStateToProps = () => { + const getGlobalQueries = inputsSelectors.globalQuery(); + const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); + const mapStateToProps = (state: State, { timelineId }: EventDetailsFooterProps) => { + return { + globalQuery: getGlobalQueries(state), + timelineQuery: getTimelineQuery(state, timelineId), + }; + }; + return mapStateToProps; +}; + +const connector = connect(makeMapStateToProps); + +type PropsFromRedux = ConnectedProps; + +export const EventDetailsFooter = connector(React.memo(EventDetailsFooterComponent)); diff --git a/x-pack/plugins/timelines/public/container/use_update_alerts.ts b/x-pack/plugins/timelines/public/container/use_update_alerts.ts index 7f42ddc6e8211..b38c3b9a71fef 100644 --- a/x-pack/plugins/timelines/public/container/use_update_alerts.ts +++ b/x-pack/plugins/timelines/public/container/use_update_alerts.ts @@ -17,6 +17,8 @@ import { /** * Update alert status by query + * + * @param useDetectionEngine logic flag for using the regular Detection Engine URL or the RAC URL * * @param status to update to('open' / 'closed' / 'acknowledged') * @param index index to be updated @@ -26,7 +28,7 @@ import { * @throws An error if response is not OK */ export const useUpdateAlertsStatus = ( - timelineId: string + useDetectionEngine: boolean = false ): { updateAlertStatus: (params: { status: AlertStatus; @@ -37,7 +39,7 @@ export const useUpdateAlertsStatus = ( const { http } = useKibana().services; return { updateAlertStatus: async ({ status, index, query }) => { - if (['detections-page', 'detections-rules-details-page'].includes(timelineId)) { + if (useDetectionEngine) { return http!.fetch(DETECTION_ENGINE_SIGNALS_STATUS_URL, { method: 'POST', body: JSON.stringify({ status, query }), @@ -51,5 +53,3 @@ export const useUpdateAlertsStatus = ( }, }; }; - -// diff --git a/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx b/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx index c9269436646ea..c6e0e13c4dcb4 100644 --- a/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx +++ b/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx @@ -28,7 +28,7 @@ export const useStatusBulkActionItems = ({ onUpdateFailure, timelineId, }: StatusBulkActionsProps) => { - const { updateAlertStatus } = useUpdateAlertsStatus(timelineId ?? ''); + const { updateAlertStatus } = useUpdateAlertsStatus(timelineId != null); const { addSuccess, addError, addWarning } = useAppToasts(); const onAlertStatusUpdateSuccess = useCallback( From df971b7dc90b844c83d561faaa57730d8e9810d5 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 12 Oct 2021 16:46:23 +0200 Subject: [PATCH 58/73] [Exploratory view] Render content only on expand (#114237) --- .../shared/exploratory_view/series_editor/series.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series.tsx index 11f96afe7ceab..d320b84c6a684 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { EuiFlexItem, EuiFlexGroup, EuiPanel, EuiAccordion, EuiSpacer } from '@elastic/eui'; @@ -47,6 +47,14 @@ export function Series({ item, isExpanded, toggleExpanded }: Props) { seriesId: id, }; + const [isExapndedOnce, setIsExapndedOnce] = useState(false); + + useEffect(() => { + if (isExpanded) { + setIsExapndedOnce(true); + } + }, [isExpanded]); + return ( - + {isExapndedOnce && } From ba8abc41516d8778f11cfdd8e12580adc9d7a79f Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 12 Oct 2021 16:58:37 +0200 Subject: [PATCH 59/73] [Vega] Improve error message in case of invalid $schema URL (#114459) * :bug: Catch the schema parser and provide a better error message * :globe_with_meridians: Add i18n --- .../public/data_model/vega_parser.test.js | 14 +++++++ .../vega/public/data_model/vega_parser.ts | 40 ++++++++++++------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js index cfeed174307ac..13c17b8f4c38f 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js @@ -81,6 +81,20 @@ describe(`VegaParser.parseAsync`, () => { }) ) ); + + test(`should return a specific error in case of $schema URL not valid`, async () => { + const vp = new VegaParser({ + $schema: 'https://vega.github.io/schema/vega-lite/v4.jsonanythingtobreakthis', + mark: 'circle', + encoding: { row: { field: 'a' } }, + }); + + await vp.parseAsync(); + + expect(vp.error).toBe( + 'The URL for the JSON "$schema" is incorrect. Correct the URL, then click Update.' + ); + }); }); describe(`VegaParser._setDefaultValue`, () => { diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts index 9000fed7f6116..bf2a6be25c71a 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts @@ -553,25 +553,37 @@ The URL is an identifier only. Kibana and your browser will never access this UR * @private */ private parseSchema(spec: VegaSpec) { - const schema = schemaParser(spec.$schema); - const isVegaLite = schema.library === 'vega-lite'; - const libVersion = isVegaLite ? vegaLiteVersion : vegaVersion; + try { + const schema = schemaParser(spec.$schema); + const isVegaLite = schema.library === 'vega-lite'; + const libVersion = isVegaLite ? vegaLiteVersion : vegaVersion; - if (versionCompare(schema.version, libVersion) > 0) { - this._onWarning( - i18n.translate('visTypeVega.vegaParser.notValidLibraryVersionForInputSpecWarningMessage', { + if (versionCompare(schema.version, libVersion) > 0) { + this._onWarning( + i18n.translate( + 'visTypeVega.vegaParser.notValidLibraryVersionForInputSpecWarningMessage', + { + defaultMessage: + 'The input spec uses {schemaLibrary} {schemaVersion}, but current version of {schemaLibrary} is {libraryVersion}.', + values: { + schemaLibrary: schema.library, + schemaVersion: schema.version, + libraryVersion: libVersion, + }, + } + ) + ); + } + + return { isVegaLite, libVersion }; + } catch (e) { + throw Error( + i18n.translate('visTypeVega.vegaParser.notValidSchemaForInputSpec', { defaultMessage: - 'The input spec uses {schemaLibrary} {schemaVersion}, but current version of {schemaLibrary} is {libraryVersion}.', - values: { - schemaLibrary: schema.library, - schemaVersion: schema.version, - libraryVersion: libVersion, - }, + 'The URL for the JSON "$schema" is incorrect. Correct the URL, then click Update.', }) ); } - - return { isVegaLite, libVersion }; } /** From f4ef2b116be5f92dc673c385e5968ae4b1fda0f6 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Tue, 12 Oct 2021 11:18:13 -0400 Subject: [PATCH 60/73] [buildkite] buildkite dependencies need to install before print_agent_links (#114573) --- .buildkite/scripts/lifecycle/pre_command.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.buildkite/scripts/lifecycle/pre_command.sh b/.buildkite/scripts/lifecycle/pre_command.sh index be31bb74ef668..cae6a07708d46 100755 --- a/.buildkite/scripts/lifecycle/pre_command.sh +++ b/.buildkite/scripts/lifecycle/pre_command.sh @@ -4,16 +4,17 @@ set -euo pipefail source .buildkite/scripts/common/util.sh -node .buildkite/scripts/lifecycle/print_agent_links.js || true - -echo '--- Job Environment Setup' +BUILDKITE_TOKEN="$(retry 5 5 vault read -field=buildkite_token_all_jobs secret/kibana-issues/dev/buildkite-ci)" +export BUILDKITE_TOKEN +echo '--- Install buildkite dependencies' cd '.buildkite' retry 5 15 yarn install cd - -BUILDKITE_TOKEN="$(retry 5 5 vault read -field=buildkite_token_all_jobs secret/kibana-issues/dev/buildkite-ci)" -export BUILDKITE_TOKEN +node .buildkite/scripts/lifecycle/print_agent_links.js || true + +echo '--- Job Environment Setup' # Set up a custom ES Snapshot Manifest if one has been specified for this build { From 435404e9614edb067778a7cadf5a58a460e86adb Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Tue, 12 Oct 2021 10:23:01 -0500 Subject: [PATCH 61/73] [Stack Monitoring] Fix blank page between loading page and overview (#114550) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/pages/loading_page.tsx | 10 +++++++++- .../monitoring/public/application/route_init.tsx | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx b/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx index d5c1bcf80c23e..ebc43dd5c627e 100644 --- a/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx @@ -15,12 +15,20 @@ import { CODE_PATH_ELASTICSEARCH } from '../../../common/constants'; const CODE_PATHS = [CODE_PATH_ELASTICSEARCH]; -export const LoadingPage = () => { +export const LoadingPage = ({ staticLoadingState }: { staticLoadingState?: boolean }) => { const { clusters, loaded } = useClusters(null, undefined, CODE_PATHS); const title = i18n.translate('xpack.monitoring.loading.pageTitle', { defaultMessage: 'Loading', }); + if (staticLoadingState) { + return ( + + ; + + ); + } + return ( {loaded === false ? : renderRedirections(clusters)} diff --git a/x-pack/plugins/monitoring/public/application/route_init.tsx b/x-pack/plugins/monitoring/public/application/route_init.tsx index 8a11df3de50ae..092b3f54036c9 100644 --- a/x-pack/plugins/monitoring/public/application/route_init.tsx +++ b/x-pack/plugins/monitoring/public/application/route_init.tsx @@ -9,6 +9,7 @@ import { Route, Redirect, useLocation } from 'react-router-dom'; import { useClusters } from './hooks/use_clusters'; import { GlobalStateContext } from './contexts/global_state_context'; import { getClusterFromClusters } from '../lib/get_cluster_from_clusters'; +import { LoadingPage } from './pages/loading_page'; export interface ComponentProps { clusters: []; @@ -66,7 +67,9 @@ export const RouteInit: React.FC = ({ - ) : null; + ) : ( + + ); }; const isExpired = (license: any): boolean => { From 44db452d53f90dac40a4c8c1e01ccfb9a0248ff7 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Tue, 12 Oct 2021 11:23:44 -0400 Subject: [PATCH 62/73] Using task runner uuid to differentiate between task instances --- .../task_manager/server/task_pool.test.ts | 22 +++++++++++++++++++ .../plugins/task_manager/server/task_pool.ts | 15 +++++++++---- .../task_running/ephemeral_task_runner.ts | 10 +++++++++ .../server/task_running/task_runner.ts | 11 ++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/task_manager/server/task_pool.test.ts b/x-pack/plugins/task_manager/server/task_pool.test.ts index 05eb7bd1b43e1..fca599a2d8981 100644 --- a/x-pack/plugins/task_manager/server/task_pool.test.ts +++ b/x-pack/plugins/task_manager/server/task_pool.test.ts @@ -357,6 +357,27 @@ describe('TaskPool', () => { ); }); + test('only allows one task with the same id in the task pool', async () => { + const logger = loggingSystemMock.create().get(); + const pool = new TaskPool({ + maxWorkers$: of(1), + logger, + }); + + const shouldRun = mockRun(); + const shouldNotRun = mockRun(); + + const taskId = uuid.v4(); + const task1 = mockTask({ id: taskId, run: shouldRun }); + const task2 = mockTask({ id: taskId, run: shouldNotRun }); + + await pool.run([task1]); + await pool.run([task2]); + + expect(shouldRun).toHaveBeenCalledTimes(1); + expect(shouldNotRun).not.toHaveBeenCalled(); + }); + function mockRun() { return jest.fn(async () => { await sleep(0); @@ -367,6 +388,7 @@ describe('TaskPool', () => { function mockTask(overrides = {}) { return { isExpired: false, + taskUuid: uuid.v4(), id: uuid.v4(), cancel: async () => undefined, markTaskAsRunning: jest.fn(async () => true), diff --git a/x-pack/plugins/task_manager/server/task_pool.ts b/x-pack/plugins/task_manager/server/task_pool.ts index d394214e6c778..a18be88c419ea 100644 --- a/x-pack/plugins/task_manager/server/task_pool.ts +++ b/x-pack/plugins/task_manager/server/task_pool.ts @@ -116,7 +116,14 @@ export class TaskPool { tasksToRun .filter((taskRunner) => !this.tasksInPool.has(taskRunner.id)) .map(async (taskRunner) => { - this.tasksInPool.set(taskRunner.id, taskRunner); + // We use taskRunner.taskUuid instead of taskRunner.id as key for the task pool map because + // task cancellation is a non-blocking procedure. We calculate the expiration and immediately remove + // the task from the task pool. There is a race condition that can occur when a recurring tasks's schedule + // matches its timeout value. A new instance of the task can be claimed and added to the task pool before + // the cancel function (meant for the previous instance of the task) is actually called. This means the wrong + // task instance is cancelled. We introduce the taskUuid to differentiate between these overlapping instances and + // ensure that the correct task instance is cancelled. + this.tasksInPool.set(taskRunner.taskUuid, taskRunner); return taskRunner .markTaskAsRunning() .then((hasTaskBeenMarkAsRunning: boolean) => @@ -170,12 +177,12 @@ export class TaskPool { } }) .then(() => { - this.tasksInPool.delete(taskRunner.id); + this.tasksInPool.delete(taskRunner.taskUuid); }); } private handleFailureOfMarkAsRunning(task: TaskRunner, err: Error) { - this.tasksInPool.delete(task.id); + this.tasksInPool.delete(task.taskUuid); this.logger.error(`Failed to mark Task ${task.toString()} as running: ${err.message}`); } @@ -203,7 +210,7 @@ export class TaskPool { private async cancelTask(task: TaskRunner) { try { this.logger.debug(`Cancelling task ${task.toString()}.`); - this.tasksInPool.delete(task.id); + this.tasksInPool.delete(task.taskUuid); await task.cancel(); } catch (err) { this.logger.error(`Failed to cancel task ${task.toString()}: ${err}`); diff --git a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts index 358a8003382b0..701b44f73db25 100644 --- a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts @@ -12,6 +12,7 @@ */ import apm from 'elastic-apm-node'; +import uuid from 'uuid'; import { withSpan } from '@kbn/apm-utils'; import { identity } from 'lodash'; import { Logger, ExecutionContextStart } from '../../../../../src/core/server'; @@ -75,6 +76,7 @@ export class EphemeralTaskManagerRunner implements TaskRunner { private beforeRun: Middleware['beforeRun']; private beforeMarkRunning: Middleware['beforeMarkRunning']; private onTaskEvent: (event: TaskRun | TaskMarkRunning) => void; + private uuid: string; private readonly executionContext: ExecutionContextStart; /** @@ -102,6 +104,7 @@ export class EphemeralTaskManagerRunner implements TaskRunner { this.beforeMarkRunning = beforeMarkRunning; this.onTaskEvent = onTaskEvent; this.executionContext = executionContext; + this.uuid = uuid.v4(); } /** @@ -111,6 +114,13 @@ export class EphemeralTaskManagerRunner implements TaskRunner { return this.instance.task.id; } + /** + * Gets the unique uuid of this task instance. + */ + public get taskUuid() { + return `${this.id}-${this.uuid}`; + } + /** * Gets the task type of this task instance. */ diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index 919360952ebd4..2074e4715bb57 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -12,6 +12,7 @@ */ import apm from 'elastic-apm-node'; +import uuid from 'uuid'; import { withSpan } from '@kbn/apm-utils'; import { performance } from 'perf_hooks'; import { identity, defaults, flow } from 'lodash'; @@ -69,6 +70,7 @@ export interface TaskRunner { markTaskAsRunning: () => Promise; run: () => Promise>; id: string; + taskUuid: string; stage: string; isEphemeral?: boolean; toString: () => string; @@ -142,6 +144,7 @@ export class TaskManagerRunner implements TaskRunner { private beforeMarkRunning: Middleware['beforeMarkRunning']; private onTaskEvent: (event: TaskRun | TaskMarkRunning) => void; private defaultMaxAttempts: number; + private uuid: string; private readonly executionContext: ExecutionContextStart; /** @@ -174,6 +177,7 @@ export class TaskManagerRunner implements TaskRunner { this.onTaskEvent = onTaskEvent; this.defaultMaxAttempts = defaultMaxAttempts; this.executionContext = executionContext; + this.uuid = uuid.v4(); } /** @@ -183,6 +187,13 @@ export class TaskManagerRunner implements TaskRunner { return this.instance.task.id; } + /** + * Gets the unique uuid of this task instance. + */ + public get taskUuid() { + return `${this.id}-${this.uuid}`; + } + /** * Gets the task type of this task instance. */ From fa69602b343bde7d5375ed2d2c732bf628b9ab28 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 12 Oct 2021 17:32:32 +0200 Subject: [PATCH 63/73] [Lens] Fix Metric visualization scale (#113956) * :bug: Fix metric rescale * :camera_flash: Restored old snapshots * :bug: Extend the fix to all scenarios * :camera_flash: Refresh snapshots for new fix Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../metric_visualization/expression.test.tsx | 20 ++++++++++++++----- .../metric_visualization/expression.tsx | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx b/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx index a3ac5b5837772..db70a7c8508e5 100644 --- a/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx @@ -90,7 +90,9 @@ describe('metric_expression', () => { reportDescription="Fancy chart description" reportTitle="My fanci metric chart" > - +
{ reportDescription="Fancy chart description" reportTitle="My fanci metric chart" > - +
{ reportDescription="" reportTitle="" > - +
{ reportDescription="" reportTitle="" > - +
{ reportDescription="" reportTitle="" > - +
- +
{value}
From 917807e7a342de15f704c7674574f2494bc82dce Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Tue, 12 Oct 2021 16:32:44 +0100 Subject: [PATCH 64/73] Telemetry: update security filterlist. (#114495) --- .../server/lib/telemetry/filters.ts | 5 +++++ .../server/lib/telemetry/sender.test.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts index a29f195ed5ecc..ee162fb76f95b 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts @@ -14,6 +14,7 @@ export interface AllowlistFields { // Allow list process fields within events. This includes "process" and "Target.process".' const allowlistProcessFields: AllowlistFields = { args: true, + entity_id: true, name: true, executable: true, code_signature: true, @@ -30,6 +31,9 @@ const allowlistProcessFields: AllowlistFields = { dll: true, malware_signature: true, memory_region: true, + real: { + entity_id: true, + }, token: { integrity_level_name: true, }, @@ -49,6 +53,7 @@ const allowlistBaseEventFields: AllowlistFields = { original_file_name: true, }, }, + dns: true, event: true, file: { extension: true, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts index 21e6b2cf6d9c4..46ed0b1f0bfb6 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts @@ -36,6 +36,11 @@ describe('TelemetryEventsSender', () => { event: { kind: 'alert', }, + dns: { + question: { + name: 'test-dns', + }, + }, agent: { name: 'test', }, @@ -79,6 +84,7 @@ describe('TelemetryEventsSender', () => { nope: 'nope', executable: null, // null fields are never allowlisted working_directory: '/some/usr/dir', + entity_id: 'some_entity_id', }, Responses: '{ "result": 0 }', // >= 7.15 Target: { @@ -102,6 +108,11 @@ describe('TelemetryEventsSender', () => { event: { kind: 'alert', }, + dns: { + question: { + name: 'test-dns', + }, + }, agent: { name: 'test', }, @@ -139,6 +150,7 @@ describe('TelemetryEventsSender', () => { process: { name: 'foo.exe', working_directory: '/some/usr/dir', + entity_id: 'some_entity_id', }, Responses: '{ "result": 0 }', Target: { From 2c2b8e388ade50362464924e1e9b19c62b6c06b4 Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Tue, 12 Oct 2021 08:49:11 -0700 Subject: [PATCH 65/73] [Security Solution][Platform] - Bug fix when loading a saved query in detections (#114347) Bug in checking === for null when possibility of undefined, added tests. --- .../components/url_state/helpers.test.ts | 57 ++++++++++++++++++- .../common/components/url_state/helpers.ts | 7 ++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/url_state/helpers.test.ts b/x-pack/plugins/security_solution/public/common/components/url_state/helpers.test.ts index 8a678be0616b9..ba806da195461 100644 --- a/x-pack/plugins/security_solution/public/common/components/url_state/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/url_state/helpers.test.ts @@ -6,7 +6,8 @@ */ import { navTabs } from '../../../app/home/home_navigations'; -import { getTitle } from './helpers'; +import { getTitle, isQueryStateEmpty } from './helpers'; +import { CONSTANTS } from './constants'; describe('Helpers Url_State', () => { describe('getTitle', () => { @@ -31,4 +32,58 @@ describe('Helpers Url_State', () => { expect(result).toEqual(''); }); }); + + describe('isQueryStateEmpty', () => { + test('returns true if queryState is undefined', () => { + const result = isQueryStateEmpty(undefined, CONSTANTS.savedQuery); + expect(result).toBeTruthy(); + }); + + test('returns true if queryState is null', () => { + const result = isQueryStateEmpty(null, CONSTANTS.savedQuery); + expect(result).toBeTruthy(); + }); + + test('returns true if url key is "query" and queryState is empty string', () => { + const result = isQueryStateEmpty({}, CONSTANTS.appQuery); + expect(result).toBeTruthy(); + }); + + test('returns false if url key is "query" and queryState is not empty', () => { + const result = isQueryStateEmpty( + { query: { query: '*:*' }, language: 'kuery' }, + CONSTANTS.appQuery + ); + expect(result).toBeFalsy(); + }); + + test('returns true if url key is "filters" and queryState is empty', () => { + const result = isQueryStateEmpty([], CONSTANTS.filters); + expect(result).toBeTruthy(); + }); + + test('returns false if url key is "filters" and queryState is not empty', () => { + const result = isQueryStateEmpty( + [{ query: { query: '*:*' }, meta: { key: '123' } }], + CONSTANTS.filters + ); + expect(result).toBeFalsy(); + }); + + // TODO: Is this a bug, or intended? + test('returns false if url key is "timeline" and queryState is empty', () => { + const result = isQueryStateEmpty({}, CONSTANTS.timeline); + expect(result).toBeFalsy(); + }); + + test('returns true if url key is "timeline" and queryState id is empty string', () => { + const result = isQueryStateEmpty({ id: '', isOpen: true }, CONSTANTS.timeline); + expect(result).toBeTruthy(); + }); + + test('returns false if url key is "timeline" and queryState is not empty', () => { + const result = isQueryStateEmpty({ id: '123', isOpen: true }, CONSTANTS.timeline); + expect(result).toBeFalsy(); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/url_state/helpers.ts b/x-pack/plugins/security_solution/public/common/components/url_state/helpers.ts index ba09ed914dc68..5b6bb0400ccdf 100644 --- a/x-pack/plugins/security_solution/public/common/components/url_state/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/components/url_state/helpers.ts @@ -199,8 +199,11 @@ export const updateTimerangeUrl = ( return timeRange; }; -export const isQueryStateEmpty = (queryState: ValueUrlState | null, urlKey: KeyUrlState) => - queryState === null || +export const isQueryStateEmpty = ( + queryState: ValueUrlState | undefined | null, + urlKey: KeyUrlState +): boolean => + queryState == null || (urlKey === CONSTANTS.appQuery && isEmpty((queryState as Query).query)) || (urlKey === CONSTANTS.filters && isEmpty(queryState)) || (urlKey === CONSTANTS.timeline && (queryState as TimelineUrl).id === ''); From 86af44854c40b5c343ca82c638b3ac13b6dd140c Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Tue, 12 Oct 2021 11:02:41 -0500 Subject: [PATCH 66/73] [DOCS] Reformats the Logs settings tables into definition lists (#114140) --- .../general-infra-logs-ui-settings.asciidoc | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/docs/settings/general-infra-logs-ui-settings.asciidoc b/docs/settings/general-infra-logs-ui-settings.asciidoc index 282239dcf166c..1e6dcf012206b 100644 --- a/docs/settings/general-infra-logs-ui-settings.asciidoc +++ b/docs/settings/general-infra-logs-ui-settings.asciidoc @@ -1,31 +1,28 @@ -[cols="2*<"] -|=== -| `xpack.infra.enabled` - | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] - Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. -| `xpack.infra.sources.default.logAlias` - | Index pattern for matching indices that contain log data. Defaults to `filebeat-*,kibana_sample_data_logs*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. +`xpack.infra.enabled`:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. -| `xpack.infra.sources.default.metricAlias` - | Index pattern for matching indices that contain Metricbeat data. Defaults to `metricbeat-*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. +`xpack.infra.sources.default.logAlias`:: +Index pattern for matching indices that contain log data. Defaults to `filebeat-*,kibana_sample_data_logs*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. -| `xpack.infra.sources.default.fields.timestamp` - | Timestamp used to sort log entries. Defaults to `@timestamp`. +`xpack.infra.sources.default.metricAlias`:: +Index pattern for matching indices that contain Metricbeat data. Defaults to `metricbeat-*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. -| `xpack.infra.sources.default.fields.message` - | Fields used to display messages in the Logs app. Defaults to `['message', '@message']`. +`xpack.infra.sources.default.fields.timestamp`:: +Timestamp used to sort log entries. Defaults to `@timestamp`. -| `xpack.infra.sources.default.fields.tiebreaker` - | Field used to break ties between two entries with the same timestamp. Defaults to `_doc`. +`xpack.infra.sources.default.fields.message`:: +Fields used to display messages in the Logs app. Defaults to `['message', '@message']`. -| `xpack.infra.sources.default.fields.host` - | Field used to identify hosts. Defaults to `host.name`. +`xpack.infra.sources.default.fields.tiebreaker`:: +Field used to break ties between two entries with the same timestamp. Defaults to `_doc`. -| `xpack.infra.sources.default.fields.container` - | Field used to identify Docker containers. Defaults to `container.id`. +`xpack.infra.sources.default.fields.host`:: +Field used to identify hosts. Defaults to `host.name`. -| `xpack.infra.sources.default.fields.pod` - | Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. +`xpack.infra.sources.default.fields.container`:: +Field used to identify Docker containers. Defaults to `container.id`. -|=== +`xpack.infra.sources.default.fields.pod`:: +Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. \ No newline at end of file From be0a1e6c00ad87dd341e63bdb52ea033dbd5fbc1 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Tue, 12 Oct 2021 11:07:38 -0500 Subject: [PATCH 67/73] [DOCS] Reformats the Machine learning settings tables into definition lists (#114143) --- docs/settings/ml-settings.asciidoc | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/settings/ml-settings.asciidoc b/docs/settings/ml-settings.asciidoc index 59fa236e08275..e67876c76df0d 100644 --- a/docs/settings/ml-settings.asciidoc +++ b/docs/settings/ml-settings.asciidoc @@ -11,18 +11,14 @@ enabled by default. [[general-ml-settings-kb]] ==== General {ml} settings -[cols="2*<"] -|=== -| `xpack.ml.enabled` {ess-icon} - | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] - Set to `true` (default) to enable {kib} {ml-features}. + - + - If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} - instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, - you can still use the {ml} APIs. To disable {ml} entirely, see the - {ref}/ml-settings.html[{es} {ml} settings]. - -|=== +`xpack.ml.enabled` {ess-icon}:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Set to `true` (default) to enable {kib} {ml-features}. + ++ +If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} +instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, +you can still use the {ml} APIs. To disable {ml} entirely, refer to +{ref}/ml-settings.html[{es} {ml} settings]. [[advanced-ml-settings-kb]] ==== Advanced {ml} settings From 511c0859449637039d151f3de78a23065e46d908 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Tue, 12 Oct 2021 11:08:02 -0500 Subject: [PATCH 68/73] [DOCS] Reformats the Search sessions settings tables into definition lists (#114145) --- .../search-sessions-settings.asciidoc | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/docs/settings/search-sessions-settings.asciidoc b/docs/settings/search-sessions-settings.asciidoc index abd6a8f12b568..7b03cd23a9023 100644 --- a/docs/settings/search-sessions-settings.asciidoc +++ b/docs/settings/search-sessions-settings.asciidoc @@ -7,37 +7,26 @@ Configure the search session settings in your `kibana.yml` configuration file. +`xpack.data_enhanced.search.sessions.enabled` {ess-icon}:: +Set to `true` (default) to enable search sessions. -[cols="2*<"] -|=== -a| `xpack.data_enhanced.` -`search.sessions.enabled` {ess-icon} -| Set to `true` (default) to enable search sessions. +`xpack.data_enhanced.search.sessions.trackingInterval` {ess-icon}:: +The frequency for updating the state of a search session. The default is `10s`. -a| `xpack.data_enhanced.` -`search.sessions.trackingInterval` {ess-icon} -| The frequency for updating the state of a search session. The default is `10s`. - -a| `xpack.data_enhanced.` -`search.sessions.pageSize` {ess-icon} -| How many search sessions {kib} processes at once while monitoring +`xpack.data_enhanced.search.sessions.pageSize` {ess-icon}:: +How many search sessions {kib} processes at once while monitoring session progress. The default is `100`. -a| `xpack.data_enhanced.` -`search.sessions.notTouchedTimeout` {ess-icon} -| How long {kib} stores search results from unsaved sessions, +`xpack.data_enhanced.search.sessions.notTouchedTimeout` {ess-icon}:: +How long {kib} stores search results from unsaved sessions, after the last search in the session completes. The default is `5m`. -a| `xpack.data_enhanced.` -`search.sessions.notTouchedInProgressTimeout` {ess-icon} -| How long a search session can run after a user navigates away without saving a session. The default is `1m`. +`xpack.data_enhanced.search.sessions.notTouchedInProgressTimeout` {ess-icon}:: +How long a search session can run after a user navigates away without saving a session. The default is `1m`. -a| `xpack.data_enhanced.` -`search.sessions.maxUpdateRetries` {ess-icon} -| How many retries {kib} can perform while attempting to save a search session. The default is `3`. +`xpack.data_enhanced.search.sessions.maxUpdateRetries` {ess-icon}:: +How many retries {kib} can perform while attempting to save a search session. The default is `3`. -a| `xpack.data_enhanced.` -`search.sessions.defaultExpiration` {ess-icon} -| How long search session results are stored before they are deleted. +`xpack.data_enhanced.search.sessions.defaultExpiration` {ess-icon}:: +How long search session results are stored before they are deleted. Extending a search session resets the expiration by the same value. The default is `7d`. -|=== From 9594574d65df746613d485ee3a6676bf3c0816f1 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Tue, 12 Oct 2021 11:08:47 -0500 Subject: [PATCH 69/73] [DOCS] Reformats the Spaces settings tables into definition lists (#114146) --- docs/settings/spaces-settings.asciidoc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/settings/spaces-settings.asciidoc b/docs/settings/spaces-settings.asciidoc index 8504464da1dfb..30b7beceb70ba 100644 --- a/docs/settings/spaces-settings.asciidoc +++ b/docs/settings/spaces-settings.asciidoc @@ -12,17 +12,13 @@ roles when Security is enabled. [[spaces-settings]] ==== Spaces settings -[cols="2*<"] -|=== -| `xpack.spaces.enabled` - | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] - Set to `true` (default) to enable Spaces in {kib}. - This setting is deprecated. Starting in 8.0, it will not be possible to disable this plugin. +`xpack.spaces.enabled`:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Set to `true` (default) to enable Spaces in {kib}. +This setting is deprecated. Starting in 8.0, it will not be possible to disable this plugin. -| `xpack.spaces.maxSpaces` - | The maximum amount of Spaces that can be used with this instance of {kib}. Some operations - in {kib} return all spaces using a single `_search` from {es}, so this must be - set lower than the `index.max_result_window` in {es}. - Defaults to `1000`. - -|=== +`xpack.spaces.maxSpaces`:: +The maximum amount of Spaces that can be used with this instance of {kib}. Some operations +in {kib} return all spaces using a single `_search` from {es}, so this must be +set lower than the `index.max_result_window` in {es}. +Defaults to `1000`. From 103869509c9e2253499c662a22001e38b06e0088 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Tue, 12 Oct 2021 12:12:34 -0400 Subject: [PATCH 70/73] [Security Solution] [Platform] Utilize SO resolve api for reading rules by `id` (#112478) * added outcome to backend routes * adds so resolved property alias_target_id to response * adds UI portion * working URL redirect on aliasMatch - todo -> update rule details page refresh button to use SO resolve. * cleanup * fix integration tests * fix jest tests * cleanup types * fix eslint.. I think vs code formatted this * WIP - undo me, working index.test.ts function * WIP - also undo me, probably * working test for aliasMatch, need to add test for outcome = conflict * add conflict callout when SO resolve yields conflict outcome * code cleanup * fix type issues * small cleanup, fix jest test after undoing changes for getFailingRuleStatus * cleanup tests * add alias_target_id to response validation too * unit test changes * update tests again * add all dependencies to useEffect and prefer useMemo * add type cast * adds integration tests for different outcomes after mocking a migrated rule leading to an aliasMatch and a migrated rule + accidental inserted rule to lead to a conflict. Also removes the outcome property if it is an exactMatch * remove unused import * fix test * functional WIP * cleanup * cleanup * finishing touches to address PR review comments * remove console.error * fix bug where spaces was not typed correctly in the plugin start method here https://github.com/elastic/kibana/pull/113983 --- .../schemas/common/schemas.ts | 12 + .../schemas/request/rule_schemas.ts | 4 + .../schemas/response/rules_schema.ts | 4 + .../detection_engine/rules/types.ts | 2 + .../rules/details/failure_history.test.tsx | 68 ++- .../rules/details/failure_history.tsx | 12 +- .../rules/details/index.test.tsx | 200 +++++++-- .../detection_engine/rules/details/index.tsx | 50 +++ .../use_hosts_risk_score.ts | 2 +- .../plugins/security_solution/public/types.ts | 2 +- .../routes/__mocks__/request_responses.ts | 20 +- .../routes/rules/delete_rules_route.test.ts | 6 +- .../routes/rules/read_rules_route.test.ts | 41 ++ .../detection_engine/rules/read_rules.test.ts | 18 +- .../lib/detection_engine/rules/read_rules.ts | 12 +- .../lib/detection_engine/rules/types.ts | 4 +- .../rules/update_rules.test.ts | 14 +- .../schemas/rule_converters.ts | 9 +- .../basic/tests/index.ts | 2 +- .../security_and_spaces/tests/index.ts | 1 + .../tests/resolve_read_rules.ts | 160 +++++++ .../detection_engine_api_integration/utils.ts | 33 +- .../resolve_read_rules/7_14/data.json | 101 +++++ .../resolve_read_rules/7_14/mappings.json | 397 ++++++++++++++++++ 24 files changed, 1101 insertions(+), 73 deletions(-) create mode 100644 x-pack/test/detection_engine_api_integration/security_and_spaces/tests/resolve_read_rules.ts create mode 100644 x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/data.json create mode 100644 x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/mappings.json diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index a9f7d96f1eb2e..3933d7e39275e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -35,6 +35,18 @@ export type Description = t.TypeOf; export const descriptionOrUndefined = t.union([description, t.undefined]); export type DescriptionOrUndefined = t.TypeOf; +// outcome is a property of the saved object resolve api +// will tell us info about the rule after 8.0 migrations +export const outcome = t.union([ + t.literal('exactMatch'), + t.literal('aliasMatch'), + t.literal('conflict'), +]); +export type Outcome = t.TypeOf; + +export const alias_target_id = t.string; +export type AliasTargetId = t.TypeOf; + export const enabled = t.boolean; export type Enabled = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts index 719337a231c1c..12e72fb6fc697 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts @@ -58,6 +58,8 @@ import { tags, interval, enabled, + outcome, + alias_target_id, updated_at, updated_by, created_at, @@ -150,6 +152,8 @@ const baseParams = { building_block_type, note, license, + outcome, + alias_target_id, output_index, timeline_id, timeline_title, diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts index 247829d5b9e7a..ac9329c3870f1 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts @@ -70,6 +70,8 @@ import { last_failure_message, filters, meta, + outcome, + alias_target_id, note, building_block_type, license, @@ -174,6 +176,8 @@ export const partialRulesSchema = t.partial({ last_failure_message, filters, meta, + outcome, + alias_target_id, index, namespace, note, diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index 9faed2d0646e0..ecf68fa207b70 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -108,6 +108,8 @@ export const RuleSchema = t.intersection([ throttle: t.union([t.string, t.null]), }), t.partial({ + outcome: t.union([t.literal('exactMatch'), t.literal('aliasMatch'), t.literal('conflict')]), + alias_target_id: t.string, building_block_type, anomaly_threshold: t.number, filters: t.array(t.unknown), diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx index d95b6ca9f3435..c91aade50cbae 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx @@ -6,19 +6,79 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; - -import { TestProviders } from '../../../../../common/mock'; +import { shallow, mount } from 'enzyme'; +import { + TestProviders, + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, +} from '../../../../../common/mock'; import { FailureHistory } from './failure_history'; import { useRuleStatus } from '../../../../containers/detection_engine/rules'; jest.mock('../../../../containers/detection_engine/rules'); +import { waitFor } from '@testing-library/react'; + +import '../../../../../common/mock/match_media'; + +import { createStore, State } from '../../../../../common/store'; +import { mockHistory, Router } from '../../../../../common/mock/router'; + +const state: State = { + ...mockGlobalState, +}; +const { storage } = createSecuritySolutionStorageMock(); +const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + +describe('RuleDetailsPageComponent', () => { + beforeAll(() => { + (useRuleStatus as jest.Mock).mockReturnValue([ + false, + { + status: 'succeeded', + last_failure_at: new Date().toISOString(), + last_failure_message: 'my fake failure message', + failures: [ + { + alert_id: 'myfakeid', + status_date: new Date().toISOString(), + status: 'failed', + last_failure_at: new Date().toISOString(), + last_success_at: new Date().toISOString(), + last_failure_message: 'my fake failure message', + last_look_back_date: new Date().toISOString(), // NOTE: This is no longer used on the UI, but left here in case users are using it within the API + }, + ], + }, + ]); + }); + + it('renders reported rule failures correctly', async () => { + const wrapper = mount( + + + + + + ); + + await waitFor(() => { + expect(wrapper.find('EuiBasicTable')).toHaveLength(1); + // ensure the expected error message is displayed in the table + expect(wrapper.find('EuiTableRowCell').at(2).find('div').at(1).text()).toEqual( + 'my fake failure message' + ); + }); + }); +}); + describe('FailureHistory', () => { beforeAll(() => { (useRuleStatus as jest.Mock).mockReturnValue([false, null]); }); - it('renders correctly', () => { + it('renders correctly with no statuses', () => { const wrapper = shallow(, { wrappingComponent: TestProviders, }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx index a7db7ab57f6c2..5289e34b10046 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx @@ -23,6 +23,12 @@ interface FailureHistoryProps { id?: string | null; } +const renderStatus = () => {i18n.TYPE_FAILED}; +const renderLastFailureAt = (value: string) => ( + +); +const renderLastFailureMessage = (value: string) => <>{value}; + const FailureHistoryComponent: React.FC = ({ id }) => { const [loading, ruleStatus] = useRuleStatus(id); if (loading) { @@ -36,14 +42,14 @@ const FailureHistoryComponent: React.FC = ({ id }) => { const columns: Array> = [ { name: i18n.COLUMN_STATUS_TYPE, - render: () => {i18n.TYPE_FAILED}, + render: renderStatus, truncateText: false, width: '16%', }, { field: 'last_failure_at', name: i18n.COLUMN_FAILED_AT, - render: (value: string) => , + render: renderLastFailureAt, sortable: false, truncateText: false, width: '24%', @@ -51,7 +57,7 @@ const FailureHistoryComponent: React.FC = ({ id }) => { { field: 'last_failure_message', name: i18n.COLUMN_FAILED_MSG, - render: (value: string) => <>{value}, + render: renderLastFailureMessage, sortable: false, truncateText: false, width: '60%', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx index 0c67a19e59e32..9c1667e7b4910 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx @@ -20,22 +20,51 @@ import { import { RuleDetailsPage } from './index'; import { createStore, State } from '../../../../../common/store'; import { useUserData } from '../../../../components/user_info'; +import { useRuleStatus } from '../../../../containers/detection_engine/rules'; +import { useRuleWithFallback } from '../../../../containers/detection_engine/rules/use_rule_with_fallback'; + import { useSourcererScope } from '../../../../../common/containers/sourcerer'; import { useParams } from 'react-router-dom'; import { mockHistory, Router } from '../../../../../common/mock/router'; -import { mockTimelines } from '../../../../../common/mock/mock_timelines_plugin'; + +import { useKibana } from '../../../../../common/lib/kibana'; + +import { fillEmptySeverityMappings } from '../helpers'; // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar jest.mock('../../../../../common/components/search_bar', () => ({ SiemSearchBar: () => null, })); +jest.mock('../helpers', () => { + const original = jest.requireActual('../helpers'); + return { + ...original, + fillEmptySeverityMappings: jest.fn().mockReturnValue([]), + }; +}); jest.mock('../../../../../common/components/query_bar', () => ({ QueryBar: () => null, })); jest.mock('../../../../containers/detection_engine/lists/use_lists_config'); jest.mock('../../../../../common/components/link_to'); jest.mock('../../../../components/user_info'); +jest.mock('../../../../containers/detection_engine/rules', () => { + const original = jest.requireActual('../../../../containers/detection_engine/rules'); + return { + ...original, + useRuleStatus: jest.fn(), + }; +}); +jest.mock('../../../../containers/detection_engine/rules/use_rule_with_fallback', () => { + const original = jest.requireActual( + '../../../../containers/detection_engine/rules/use_rule_with_fallback' + ); + return { + ...original, + useRuleWithFallback: jest.fn(), + }; +}); jest.mock('../../../../../common/containers/sourcerer'); jest.mock('../../../../../common/containers/use_global_time', () => ({ useGlobalTime: jest.fn().mockReturnValue({ @@ -55,41 +84,42 @@ jest.mock('react-router-dom', () => { }; }); -jest.mock('../../../../../common/lib/kibana', () => { - const original = jest.requireActual('../../../../../common/lib/kibana'); +jest.mock('../../../../../common/lib/kibana'); - return { - ...original, - useUiSetting$: jest.fn().mockReturnValue([]), - useKibana: () => ({ - services: { - application: { - ...original.useKibana().services.application, - navigateToUrl: jest.fn(), - capabilities: { - actions: jest.fn().mockReturnValue({}), - siem: { crud_alerts: true, read_alerts: true }, - }, - }, - timelines: { ...mockTimelines }, - data: { - query: { - filterManager: jest.fn().mockReturnValue({}), - }, - }, - }, - }), - useToasts: jest.fn().mockReturnValue({ - addError: jest.fn(), - addSuccess: jest.fn(), - addWarning: jest.fn(), - }), - }; -}); +const mockRedirectLegacyUrl = jest.fn(); +const mockGetLegacyUrlConflict = jest.fn(); const state: State = { ...mockGlobalState, }; + +const mockRule = { + id: 'myfakeruleid', + author: [], + severity_mapping: [], + risk_score_mapping: [], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'low', + type: 'query', + query: 'some query', + index: ['index-1'], + interval: '5m', + references: [], + actions: [], + enabled: false, + false_positives: [], + max_signals: 100, + tags: [], + threat: [], + throttle: null, + version: 1, + exceptions_list: [], +}; const { storage } = createSecuritySolutionStorageMock(); const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); @@ -101,9 +131,108 @@ describe('RuleDetailsPageComponent', () => { indicesExist: true, indexPattern: {}, }); + (useRuleStatus as jest.Mock).mockReturnValue([ + false, + { + status: 'succeeded', + last_failure_at: new Date().toISOString(), + last_failure_message: 'my fake failure message', + failures: [], + }, + ]); + (useRuleWithFallback as jest.Mock).mockReturnValue({ + error: null, + loading: false, + isExistingRule: true, + refresh: jest.fn(), + rule: { ...mockRule }, + }); + (fillEmptySeverityMappings as jest.Mock).mockReturnValue([]); + }); + + async function setup() { + const useKibanaMock = useKibana as jest.Mocked; + + // eslint-disable-next-line react-hooks/rules-of-hooks + useKibanaMock().services.spaces = { + ui: { + // @ts-expect-error + components: { getLegacyUrlConflict: mockGetLegacyUrlConflict }, + redirectLegacyUrl: mockRedirectLegacyUrl, + }, + }; + } + + it('renders correctly with no outcome property on rule', async () => { + await setup(); + + const wrapper = mount( + + + + + + ); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-page-title"]').exists()).toBe(true); + expect(mockRedirectLegacyUrl).not.toHaveBeenCalled(); + }); + }); + + it('renders correctly with outcome === "exactMatch"', async () => { + await setup(); + (useRuleWithFallback as jest.Mock).mockReturnValue({ + error: null, + loading: false, + isExistingRule: true, + refresh: jest.fn(), + rule: { ...mockRule, outcome: 'exactMatch' }, + }); + + const wrapper = mount( + + + + + + ); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-page-title"]').exists()).toBe(true); + expect(mockRedirectLegacyUrl).not.toHaveBeenCalled(); + }); }); - it('renders correctly', async () => { + it('renders correctly with outcome === "aliasMatch"', async () => { + await setup(); + (useRuleWithFallback as jest.Mock).mockReturnValue({ + error: null, + loading: false, + isExistingRule: true, + refresh: jest.fn(), + rule: { ...mockRule, outcome: 'aliasMatch' }, + }); + const wrapper = mount( + + + + + + ); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-page-title"]').exists()).toBe(true); + expect(mockRedirectLegacyUrl).toHaveBeenCalledWith(`rules/id/myfakeruleid`, `rule`); + }); + }); + + it('renders correctly when outcome = conflict', async () => { + await setup(); + (useRuleWithFallback as jest.Mock).mockReturnValue({ + error: null, + loading: false, + isExistingRule: true, + refresh: jest.fn(), + rule: { ...mockRule, outcome: 'conflict', alias_target_id: 'aliased_rule_id' }, + }); const wrapper = mount( @@ -113,6 +242,13 @@ describe('RuleDetailsPageComponent', () => { ); await waitFor(() => { expect(wrapper.find('[data-test-subj="header-page-title"]').exists()).toBe(true); + expect(mockRedirectLegacyUrl).toHaveBeenCalledWith(`rules/id/myfakeruleid`, `rule`); + expect(mockGetLegacyUrlConflict).toHaveBeenCalledWith({ + currentObjectId: 'myfakeruleid', + objectNoun: 'rule', + otherObjectId: 'aliased_rule_id', + otherObjectPath: `rules/id/aliased_rule_id`, + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 70d7faa47b9ee..492b8e461fb60 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -19,6 +19,8 @@ import { EuiToolTip, EuiWindowEvent, } from '@elastic/eui'; +import { i18n as i18nTranslate } from '@kbn/i18n'; + import { FormattedMessage } from '@kbn/i18n/react'; import { noop } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -261,6 +263,7 @@ const RuleDetailsPageComponent: React.FC = ({ capabilities: { actions }, }, timelines: timelinesUi, + spaces: spacesApi, }, } = useKibana(); const hasActionsPrivileges = useMemo(() => { @@ -277,6 +280,52 @@ const RuleDetailsPageComponent: React.FC = ({ } }, [maybeRule]); + useEffect(() => { + if (rule) { + const outcome = rule.outcome; + if (spacesApi && outcome === 'aliasMatch') { + // This rule has been resolved from a legacy URL - redirect the user to the new URL and display a toast. + const path = `rules/id/${rule.id}${window.location.search}${window.location.hash}`; + spacesApi.ui.redirectLegacyUrl( + path, + i18nTranslate.translate( + 'xpack.triggersActionsUI.sections.alertDetails.redirectObjectNoun', + { + defaultMessage: 'rule', + } + ) + ); + } + } + }, [rule, spacesApi]); + + const getLegacyUrlConflictCallout = useMemo(() => { + const outcome = rule?.outcome; + if (rule != null && spacesApi && outcome === 'conflict') { + const aliasTargetId = rule?.alias_target_id!; // This is always defined if outcome === 'conflict' + // We have resolved to one rule, but there is another one with a legacy URL associated with this page. Display a + // callout with a warning for the user, and provide a way for them to navigate to the other rule. + const otherRulePath = `rules/id/${aliasTargetId}${window.location.search}${window.location.hash}`; + return ( + <> + + {spacesApi.ui.components.getLegacyUrlConflict({ + objectNoun: i18nTranslate.translate( + 'xpack.triggersActionsUI.sections.alertDetails.redirectObjectNoun', + { + defaultMessage: 'rule', + } + ), + currentObjectId: rule.id, + otherObjectId: aliasTargetId, + otherObjectPath: otherRulePath, + })} + + ); + } + return null; + }, [rule, spacesApi]); + useEffect(() => { if (!hasIndexRead) { setTabs(ruleDetailTabs.filter(({ id }) => id !== RuleDetailTabs.alerts)); @@ -721,6 +770,7 @@ const RuleDetailsPageComponent: React.FC = ({ {ruleError} + {getLegacyUrlConflictCallout} diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts index af663bb74f54a..15cb7ef7b1c46 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts @@ -98,7 +98,7 @@ export const useHostsRiskScore = ({ useEffect(() => { if (riskyHostsFeatureEnabled && (hostName || timerange)) { - spaces.getActiveSpace().then((space) => { + spaces?.getActiveSpace().then((space) => { start({ data, timerange: timerange diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 1cec87fd35d1f..e595b905b998e 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -68,7 +68,7 @@ export interface StartPlugins { timelines: TimelinesUIStart; uiActions: UiActionsStart; ml?: MlPluginStart; - spaces: SpacesPluginStart; + spaces?: SpacesPluginStart; } export type StartServices = CoreStart & diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index c3c3ac47baf9a..200246ba1a367 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -34,7 +34,7 @@ import { getFinalizeSignalsMigrationSchemaMock } from '../../../../../common/det import { EqlSearchResponse } from '../../../../../common/detection_engine/types'; import { getSignalsMigrationStatusSchemaMock } from '../../../../../common/detection_engine/schemas/request/get_signals_migration_status_schema.mock'; import { RuleParams } from '../../schemas/rule_schemas'; -import { Alert } from '../../../../../../alerting/common'; +import { SanitizedAlert, ResolvedSanitizedRule } from '../../../../../../alerting/common'; import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; import { getPerformBulkActionSchemaMock } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema.mock'; import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; @@ -87,6 +87,13 @@ export const getReadRequest = () => query: { rule_id: 'rule-1' }, }); +export const getReadRequestWithId = (id: string) => + requestMock.create({ + method: 'get', + path: DETECTION_ENGINE_RULES_URL, + query: { id }, + }); + export const getFindRequest = () => requestMock.create({ method: 'get', @@ -362,7 +369,7 @@ export const nonRuleAlert = (isRuleRegistryEnabled: boolean) => ({ export const getAlertMock = ( isRuleRegistryEnabled: boolean, params: T -): Alert => ({ +): SanitizedAlert => ({ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', name: 'Detect Root/Admin Users', tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:false`], @@ -378,7 +385,6 @@ export const getAlertMock = ( notifyWhen: null, createdBy: 'elastic', updatedBy: 'elastic', - apiKey: null, apiKeyOwner: 'elastic', muteAll: false, mutedInstanceIds: [], @@ -389,6 +395,14 @@ export const getAlertMock = ( }, }); +export const resolveAlertMock = ( + isRuleRegistryEnabled: boolean, + params: T +): ResolvedSanitizedRule => ({ + outcome: 'exactMatch', + ...getAlertMock(isRuleRegistryEnabled, params), +}); + export const updateActionResult = (): ActionResult => ({ id: 'result-1', actionTypeId: 'action-id-1', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts index 35b3ef3d9cf85..7c447660acb45 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts @@ -8,7 +8,7 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { getEmptyFindResult, - getAlertMock, + resolveAlertMock, getDeleteRequest, getFindResultWithSingleHit, getDeleteRequestById, @@ -45,8 +45,8 @@ describe.each([ }); test('returns 200 when deleting a single rule with a valid actionClient and alertClient by id', async () => { - clients.rulesClient.get.mockResolvedValue( - getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) + clients.rulesClient.resolve.mockResolvedValue( + resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); const response = await server.inject(getDeleteRequestById(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts index d6c18088800ba..37b8228ac1e9b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts @@ -12,11 +12,14 @@ import { readRulesRoute } from './read_rules_route'; import { getEmptyFindResult, getReadRequest, + getReadRequestWithId, getFindResultWithSingleHit, nonRuleFindResult, getEmptySavedObjectsResponse, + resolveAlertMock, } from '../__mocks__/request_responses'; import { requestMock, requestContextMock, serverMock } from '../__mocks__'; +import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; describe.each([ ['Legacy', false], @@ -26,6 +29,7 @@ describe.each([ let { clients, context } = requestContextMock.createTools(); let logger: ReturnType; + const myFakeId = '99403909-ca9b-49ba-9d7a-7e5320e68d05'; beforeEach(() => { server = serverMock.create(); logger = loggingSystemMock.createLogger(); @@ -35,6 +39,12 @@ describe.each([ clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // successful transform clients.ruleExecutionLogClient.find.mockResolvedValue([]); + clients.rulesClient.resolve.mockResolvedValue({ + ...resolveAlertMock(isRuleRegistryEnabled, { + ...getQueryRuleParams(), + }), + id: myFakeId, + }); readRulesRoute(server.router, logger, isRuleRegistryEnabled); }); @@ -44,6 +54,37 @@ describe.each([ expect(response.status).toEqual(200); }); + test('returns 200 when reading a single rule outcome === exactMatch', async () => { + const response = await server.inject(getReadRequestWithId(myFakeId), context); + expect(response.status).toEqual(200); + }); + + test('returns 200 when reading a single rule outcome === aliasMatch', async () => { + clients.rulesClient.resolve.mockResolvedValue({ + ...resolveAlertMock(isRuleRegistryEnabled, { + ...getQueryRuleParams(), + }), + id: myFakeId, + outcome: 'aliasMatch', + }); + const response = await server.inject(getReadRequestWithId(myFakeId), context); + expect(response.status).toEqual(200); + }); + + test('returns 200 when reading a single rule outcome === conflict', async () => { + clients.rulesClient.resolve.mockResolvedValue({ + ...resolveAlertMock(isRuleRegistryEnabled, { + ...getQueryRuleParams(), + }), + id: myFakeId, + outcome: 'conflict', + alias_target_id: 'myaliastargetid', + }); + const response = await server.inject(getReadRequestWithId(myFakeId), context); + expect(response.status).toEqual(200); + expect(response.body.alias_target_id).toEqual('myaliastargetid'); + }); + test('returns 404 if alertClient is not available on the route', async () => { context.alerting!.getRulesClient = jest.fn(); const response = await server.inject(getReadRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts index 6f89d725a458e..2e17b91fbcd54 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts @@ -7,7 +7,11 @@ import { readRules } from './read_rules'; import { rulesClientMock } from '../../../../../alerting/server/mocks'; -import { getAlertMock, getFindResultWithSingleHit } from '../routes/__mocks__/request_responses'; +import { + resolveAlertMock, + getAlertMock, + getFindResultWithSingleHit, +} from '../routes/__mocks__/request_responses'; import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; export class TestError extends Error { @@ -33,7 +37,9 @@ describe.each([ describe('readRules', () => { test('should return the output from rulesClient if id is set but ruleId is undefined', async () => { const rulesClient = rulesClientMock.create(); - rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())); + rulesClient.resolve.mockResolvedValue( + resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) + ); const rule = await readRules({ isRuleRegistryEnabled, @@ -45,10 +51,10 @@ describe.each([ }); test('should return null if saved object found by alerts client given id is not alert type', async () => { const rulesClient = rulesClientMock.create(); - const result = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); + const result = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); // @ts-expect-error delete result.alertTypeId; - rulesClient.get.mockResolvedValue(result); + rulesClient.resolve.mockResolvedValue(result); const rule = await readRules({ isRuleRegistryEnabled, @@ -61,7 +67,7 @@ describe.each([ test('should return error if alerts client throws 404 error on get', async () => { const rulesClient = rulesClientMock.create(); - rulesClient.get.mockImplementation(() => { + rulesClient.resolve.mockImplementation(() => { throw new TestError(); }); @@ -76,7 +82,7 @@ describe.each([ test('should return error if alerts client throws error on get', async () => { const rulesClient = rulesClientMock.create(); - rulesClient.get.mockImplementation(() => { + rulesClient.resolve.mockImplementation(() => { throw new Error('Test error'); }); try { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts index 9578e3d4cb6d2..2571791164b6b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SanitizedAlert } from '../../../../../alerting/common'; +import { ResolvedSanitizedRule, SanitizedAlert } from '../../../../../alerting/common'; import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; import { RuleParams } from '../schemas/rule_schemas'; import { findRules } from './find_rules'; @@ -24,11 +24,17 @@ export const readRules = async ({ rulesClient, id, ruleId, -}: ReadRuleOptions): Promise | null> => { +}: ReadRuleOptions): Promise< + SanitizedAlert | ResolvedSanitizedRule | null +> => { if (id != null) { try { - const rule = await rulesClient.get({ id }); + const rule = await rulesClient.resolve({ id }); if (isAlertType(isRuleRegistryEnabled, rule)) { + if (rule?.outcome === 'exactMatch') { + const { outcome, ...restOfRule } = rule; + return restOfRule; + } return rule; } else { return null; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index cceda063e987b..8adf19a53f92b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -100,14 +100,14 @@ import { } from '../../../../common/detection_engine/schemas/common/schemas'; import { RulesClient, PartialAlert } from '../../../../../alerting/server'; -import { Alert, SanitizedAlert } from '../../../../../alerting/common'; +import { SanitizedAlert } from '../../../../../alerting/common'; import { SIGNALS_ID } from '../../../../common/constants'; import { PartialFilter } from '../types'; import { RuleParams } from '../schemas/rule_schemas'; import { IRuleExecutionLogClient } from '../rule_execution_log/types'; import { ruleTypeMappings } from '../signals/utils'; -export type RuleAlertType = Alert; +export type RuleAlertType = SanitizedAlert; // eslint-disable-next-line @typescript-eslint/no-explicit-any export interface IRuleStatusSOAttributes extends Record { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts index 74301f3665ff8..703be3bdd76bd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getAlertMock } from '../routes/__mocks__/request_responses'; +import { getAlertMock, resolveAlertMock } from '../routes/__mocks__/request_responses'; import { updateRules } from './update_rules'; import { getUpdateRulesOptionsMock, getUpdateMlRulesOptionsMock } from './update_rules.mock'; import { RulesClientMock } from '../../../../../alerting/server/rules_client.mock'; @@ -18,8 +18,8 @@ describe.each([ it('should call rulesClient.disable if the rule was enabled and enabled is false', async () => { const rulesOptionsMock = getUpdateRulesOptionsMock(isRuleRegistryEnabled); rulesOptionsMock.ruleUpdate.enabled = false; - (rulesOptionsMock.rulesClient as unknown as RulesClientMock).get.mockResolvedValue( - getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) + (rulesOptionsMock.rulesClient as unknown as RulesClientMock).resolve.mockResolvedValue( + resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); (rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue( getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) @@ -38,8 +38,8 @@ describe.each([ const rulesOptionsMock = getUpdateRulesOptionsMock(isRuleRegistryEnabled); rulesOptionsMock.ruleUpdate.enabled = true; - (rulesOptionsMock.rulesClient as unknown as RulesClientMock).get.mockResolvedValue({ - ...getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()), + (rulesOptionsMock.rulesClient as unknown as RulesClientMock).resolve.mockResolvedValue({ + ...resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()), enabled: false, }); (rulesOptionsMock.rulesClient as unknown as RulesClientMock).update.mockResolvedValue( @@ -63,8 +63,8 @@ describe.each([ getAlertMock(isRuleRegistryEnabled, getMlRuleParams()) ); - (rulesOptionsMock.rulesClient as unknown as RulesClientMock).get.mockResolvedValue( - getAlertMock(isRuleRegistryEnabled, getMlRuleParams()) + (rulesOptionsMock.rulesClient as unknown as RulesClientMock).resolve.mockResolvedValue( + resolveAlertMock(isRuleRegistryEnabled, getMlRuleParams()) ); await updateRules(rulesOptionsMock); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts index eef20af0e564d..240a226e86914 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts @@ -27,7 +27,7 @@ import { AppClient } from '../../../types'; import { addTags } from '../rules/add_tags'; import { DEFAULT_MAX_SIGNALS, SERVER_APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { SanitizedAlert } from '../../../../../alerting/common'; +import { ResolvedSanitizedRule, SanitizedAlert } from '../../../../../alerting/common'; import { IRuleStatusSOAttributes } from '../rules/types'; import { transformTags } from '../routes/rules/utils'; import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; @@ -281,12 +281,17 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { }; export const internalRuleToAPIResponse = ( - rule: SanitizedAlert, + rule: SanitizedAlert | ResolvedSanitizedRule, ruleStatus?: IRuleStatusSOAttributes, legacyRuleActions?: LegacyRuleActions | null ): FullResponseSchema => { const mergedStatus = ruleStatus ? mergeAlertWithSidecarStatus(rule, ruleStatus) : undefined; + const isResolvedRule = (obj: unknown): obj is ResolvedSanitizedRule => + (obj as ResolvedSanitizedRule).outcome != null; return { + // saved object properties + outcome: isResolvedRule(rule) ? rule.outcome : undefined, + alias_target_id: isResolvedRule(rule) ? rule.alias_target_id : undefined, // Alerting framework params id: rule.id, updated_at: rule.updatedAt.toISOString(), diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/index.ts b/x-pack/test/detection_engine_api_integration/basic/tests/index.ts index 802b1e78930e8..5fa4540bbe854 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { - describe('detection engine api security and spaces enabled', function () { + describe('detection engine api basic license', function () { this.tags('ciGroup1'); loadTestFile(require.resolve('./add_prepackaged_rules')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts index b4bd74172920b..1b88c4fe21b49 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts @@ -33,6 +33,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./get_prepackaged_rules_status')); loadTestFile(require.resolve('./import_rules')); loadTestFile(require.resolve('./read_rules')); + loadTestFile(require.resolve('./resolve_read_rules')); loadTestFile(require.resolve('./update_rules')); loadTestFile(require.resolve('./update_rules_bulk')); loadTestFile(require.resolve('./patch_rules_bulk')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/resolve_read_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/resolve_read_rules.ts new file mode 100644 index 0000000000000..6013398d4695d --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/resolve_read_rules.ts @@ -0,0 +1,160 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_RULES_URL } from '../../../../plugins/security_solution/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { createSignalsIndex, deleteAllAlerts, deleteSignalsIndex } from '../../utils'; + +const spaceId = '714-space'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('resolve_read_rules', () => { + describe('reading rules', () => { + beforeEach(async () => { + await createSignalsIndex(supertest); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14' + ); + }); + + afterEach(async () => { + await deleteSignalsIndex(supertest); + await deleteAllAlerts(supertest); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14' + ); + }); + + it('should create a "migrated" rule where querying for the new SO _id will resolve the new object and not return the outcome field when outcome === exactMatch', async () => { + // link to the new URL with migrated SO id 74f3e6d7-b7bb-477d-ac28-92ee22728e6e + const URL = `/s/${spaceId}${DETECTION_ENGINE_RULES_URL}?id=90e3ca0e-71f7-513a-b60a-ac678efd8887`; + const readRulesAliasMatchRes = await supertest.get(URL).set('kbn-xsrf', 'true').send(); + expect(readRulesAliasMatchRes.body.outcome).to.eql('aliasMatch'); + + // now that we have the migrated alias_target_id, let's attempt an 'exactMatch' query + // the result of which should have the outcome as undefined when querying the read rules api. + const exactMatchURL = `/s/${spaceId}${DETECTION_ENGINE_RULES_URL}?id=${readRulesAliasMatchRes.body.alias_target_id}`; + const readRulesExactMatchRes = await supertest + .get(exactMatchURL) + .set('kbn-xsrf', 'true') + .send(); + expect(readRulesExactMatchRes.body.outcome).to.eql(undefined); + }); + + it('should create a rule and a "conflicting rule" where the SO _id matches the sourceId (see legacy-url-alias SO) of a migrated rule', async () => { + // mimic a rule SO that was inserted accidentally + // we have to insert this outside of esArchiver otherwise kibana will migrate this + // and we won't have a conflict + await es.index({ + id: 'alert:90e3ca0e-71f7-513a-b60a-ac678efd8887', + index: '.kibana', + refresh: true, + body: { + alert: { + name: 'test 7.14', + tags: [ + '__internal_rule_id:82747bb8-bae0-4b59-8119-7f65ac564e14', + '__internal_immutable:false', + ], + alertTypeId: 'siem.signals', + consumer: 'siem', + params: { + author: [], + description: 'test', + ruleId: '82747bb8-bae0-4b59-8119-7f65ac564e14', + falsePositives: [], + from: 'now-3615s', + immutable: false, + license: '', + outputIndex: '.siem-signals-devin-hurley-714-space', + meta: { + from: '1h', + kibana_siem_app_url: 'http://0.0.0.0:5601/s/714-space/app/security', + }, + maxSignals: 100, + riskScore: 21, + riskScoreMapping: [], + severity: 'low', + severityMapping: [], + threat: [], + to: 'now', + references: [], + version: 1, + exceptionsList: [], + type: 'query', + language: 'kuery', + index: [ + 'apm-*-transaction*', + 'traces-apm*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + query: '*:*', + filters: [], + }, + schedule: { + interval: '15s', + }, + enabled: true, + actions: [], + throttle: null, + notifyWhen: 'onActiveAlert', + apiKeyOwner: 'elastic', + apiKey: + 'HvwrIJ8NBshJav9vf3BSEEa2P7fXLTpmEKAx2bSyBF51N2cadFkltWLRRcFnj65RXsPzvRm3VKzAde4b1iGzsjxY/IVmfGGyiO0rk6vZVJVLeMSD+CAiflnwweypoKM8WgwXJnI0Oa/SWqKMtrDiFxCcZCwIuAhS0sjenaiEuedbAuStZv513zz/clpqRKFXBydJXKyjJUQLTA==', + createdBy: 'elastic', + updatedBy: 'elastic', + createdAt: '2021-10-05T19:52:25.865Z', + updatedAt: '2021-10-05T19:52:25.865Z', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'ok', + lastExecutionDate: '2021-10-05T19:52:51.260Z', + error: null, + }, + meta: { + versionApiKeyLastmodified: '7.14.2', + }, + scheduledTaskId: 'c4005e90-2615-11ec-811e-db7211397897', + legacyId: 'c364e1e0-2615-11ec-811e-db7211397897', + }, + type: 'alert', + references: [], + namespaces: [spaceId], + originId: 'c364e1e0-2615-11ec-811e-db7211397897', + migrationVersion: { + alert: '8.0.0', + }, + coreMigrationVersion: '8.0.0', + updated_at: '2021-10-05T19:52:56.014Z', + }, + }); + + // Now that we have a rule id and a legacy-url-alias with the same id, we should have a conflict + const conflictURL = `/s/${spaceId}${DETECTION_ENGINE_RULES_URL}?id=90e3ca0e-71f7-513a-b60a-ac678efd8887`; + const readRulesConflictRes = await supertest + .get(conflictURL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(readRulesConflictRes.body.outcome).to.eql('conflict'); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/utils.ts b/x-pack/test/detection_engine_api_integration/utils.ts index ac27f06a149d9..eeae21c3b7bad 100644 --- a/x-pack/test/detection_engine_api_integration/utils.ts +++ b/x-pack/test/detection_engine_api_integration/utils.ts @@ -369,17 +369,31 @@ export const getSimpleRuleOutput = (ruleId = 'rule-1', enabled = false): Partial version: 1, }); +export const resolveSimpleRuleOutput = ( + ruleId = 'rule-1', + enabled = false +): Partial => ({ outcome: 'exactMatch', ...getSimpleRuleOutput(ruleId, enabled) }); + /** * This is the typical output of a simple rule that Kibana will output with all the defaults except * for all the server generated properties such as created_by. Useful for testing end to end tests. */ export const getSimpleRuleOutputWithoutRuleId = (ruleId = 'rule-1'): Partial => { const rule = getSimpleRuleOutput(ruleId); - // eslint-disable-next-line @typescript-eslint/naming-convention - const { rule_id, ...ruleWithoutRuleId } = rule; + const { rule_id: rId, ...ruleWithoutRuleId } = rule; return ruleWithoutRuleId; }; +/** + * This is the typical output of a simple rule that Kibana will output with all the defaults except + * for all the server generated properties such as created_by. Useful for testing end to end tests. + */ +export const resolveSimpleRuleOutputWithoutRuleId = (ruleId = 'rule-1'): Partial => { + const rule = getSimpleRuleOutput(ruleId); + const { rule_id: rId, ...ruleWithoutRuleId } = rule; + return { outcome: 'exactMatch', ...ruleWithoutRuleId }; +}; + export const getSimpleMlRuleOutput = (ruleId = 'rule-1'): Partial => { const rule = getSimpleRuleOutput(ruleId); const { query, language, index, ...rest } = rule; @@ -399,12 +413,17 @@ export const getSimpleMlRuleOutput = (ruleId = 'rule-1'): Partial = * @param supertest The supertest agent. */ export const deleteAllAlerts = async ( - supertest: SuperTest.SuperTest + supertest: SuperTest.SuperTest, + space?: string ): Promise => { await countDownTest( async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_RULES_URL}/_find?per_page=9999`) + .get( + space + ? `/s/${space}${DETECTION_ENGINE_RULES_URL}/_find?per_page=9999` + : `${DETECTION_ENGINE_RULES_URL}/_find?per_page=9999` + ) .set('kbn-xsrf', 'true') .send(); @@ -413,7 +432,11 @@ export const deleteAllAlerts = async ( })); await supertest - .post(`${DETECTION_ENGINE_RULES_URL}/_bulk_delete`) + .post( + space + ? `/s/${space}${DETECTION_ENGINE_RULES_URL}/_bulk_delete` + : `${DETECTION_ENGINE_RULES_URL}/_bulk_delete` + ) .send(ids) .set('kbn-xsrf', 'true'); diff --git a/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/data.json b/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/data.json new file mode 100644 index 0000000000000..498367c913dc0 --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/data.json @@ -0,0 +1,101 @@ +{ + "type" : "doc", + "value": { + "index" : ".kibana_1", + "id" : "space:714-space", + "source" : { + "space" : { + "name" : "714-space", + "initials" : "t", + "color" : "#B9A888", + "disabledFeatures" : [ ], + "imageUrl" : "" + }, + "type" : "space", + "references" : [ ], + "migrationVersion" : { + "space" : "6.6.0" + }, + "updated_at" : "2021-10-11T14:49:07.012Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "714-space:alert:90e3ca0e-71f7-513a-b60a-ac678efd8887", + "index": ".kibana_1", + "source": { + "alert": { + "actions": [ + ], + "alertTypeId" : "siem.signals", + "consumer" : "siem", + "apiKey": "QIUT8u0/kbOakEHSj50jDpVR90MrqOxanEscboYOoa8PxQvcA5jfHash+fqH3b+KNjJ1LpnBcisGuPkufY9j1e32gKzwGZV5Bfys87imHvygJvIM8uKiFF8bQ8Y4NTaxOJO9fAmZPrFy07ZcQMCAQz+DUTgBFqs=", + "apiKeyOwner": "elastic", + "createdAt": "2020-06-17T15:35:38.497Z", + "createdBy": "elastic", + "enabled": true, + "muteAll": false, + "mutedInstanceIds": [ + ], + "name": "always-firing-alert", + "params":{ + "author": [], + "description": "test", + "ruleId": "82747bb8-bae0-4b59-8119-7f65ac564e14", + "falsePositives": [], + "from": "now-3615s", + "immutable": false, + "license": "", + "outputIndex": ".siem-signals-devin-hurley-714-space", + "meta": { + "from": "1h", + "kibana_siem_app_url": "http://0.0.0.0:5601/s/714-space/app/security" + }, + "maxSignals": 100, + "riskScore": 21, + "riskScoreMapping": [], + "severity": "low", + "severityMapping": [], + "threat": [], + "to": "now", + "references": [], + "version": 1, + "exceptionsList": [], + "type": "query", + "language": "kuery", + "index": [ + "apm-*-transaction*", + "traces-apm*", + "auditbeat-*", + "endgame-*", + "filebeat-*", + "logs-*", + "packetbeat-*", + "winlogbeat-*" + ], + "query": "*:*", + "filters": [] + }, + "schedule": { + "interval": "1m" + }, + "scheduledTaskId": "329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "tags": [ + ], + "throttle": null, + "updatedBy": "elastic" + }, + "migrationVersion": { + "alert": "7.8.0" + }, + "references": [ + ], + "namespace": "714-space", + "type": "alert", + "updated_at": "2020-06-17T15:35:39.839Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/mappings.json b/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/mappings.json new file mode 100644 index 0000000000000..069f70badce4e --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14/mappings.json @@ -0,0 +1,397 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana": {} + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "action": "6e96ac5e648f57523879661ea72525b7", + "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", + "alert": "7b44fba6773e37c806ce290ea9b7024e", + "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", + "apm-telemetry": "3525d7c22c42bc80f5e6e9cb3f2b26a2", + "application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1", + "application_usage_transactional": "965839e75f809fefe04f92dc4d99722a", + "canvas-element": "7390014e1091044523666d97247392fc", + "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", + "cases": "32aa96a6d3855ddda53010ae2048ac22", + "cases-comments": "c2061fb929f585df57425102fa928b4b", + "cases-configure": "42711cbb311976c0687853f4c1354572", + "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", + "config": "ae24d22d5986d04124cc6568f771066f", + "dashboard": "d00f614b29a80360e1190193fd333bab", + "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", + "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", + "index-pattern": "66eccb05066c5a89924f48a9e9736499", + "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", + "inventory-view": "88fc7e12fd1b45b6f0787323ce4f18d2", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "lens": "d33c68a69ff1e78c9888dedd2164ac22", + "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", + "map": "23d7aa4a720d4938ccde3983f87bd58d", + "maps-telemetry": "bfd39d88aadadb4be597ea984d433dbe", + "metrics-explorer-view": "428e319af3e822c80a84cf87123ca35c", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "181661168bbadd1eff5902361e2a0d5c", + "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "todo": "082a2cc96a590268344d5cd74c159ac4", + "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "upgrade-assistant-reindex-operation": "296a89039fc4260292be36b1b005d8f2", + "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", + "uptime-dynamic-settings": "fcdb453a30092f022f2642db29523d80", + "url": "b675c3be8d76ecf029294d51dc7ec65d", + "visualization": "52d7a13ad68a150c4525b292d23e12cc" + } + }, + "dynamic": "strict", + "properties": { + "action": { + "properties": { + "actionTypeId": { + "type": "keyword" + }, + "config": { + "enabled": false, + "type": "object" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "secrets": { + "type": "binary" + } + } + }, + "action_task_params": { + "properties": { + "actionId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alert": { + "properties": { + "actions": { + "properties": { + "actionRef": { + "type": "keyword" + }, + "actionTypeId": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + }, + "type": "nested" + }, + "alertTypeId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "apiKeyOwner": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + }, + "legacyId": { + "type": "keyword" + }, + "createdBy": { + "type": "keyword" + }, + "updatedAt": { + "type": "date" + }, + "executionStatus": { + "properties": { + "error": { + "properties": { + "message": { + "type": "keyword" + }, + "reason": { + "type": "keyword" + } + } + }, + "lastExecutionDate": { + "type": "date" + }, + "status": { + "type": "keyword" + } + } + }, + "enabled": { + "type": "boolean" + }, + "muteAll": { + "type": "boolean" + }, + "mutedInstanceIds": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "params": { + "enabled": false, + "type": "object" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledTaskId": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "throttle": { + "type": "keyword" + }, + "updatedBy": { + "type": "keyword" + } + } + }, + "legacy-url-alias": { + "properties": { + "sourceId": { + "type": "text" + }, + "targetNamespace": { + "type": "keyword" + }, + "targetType": { + "type": "keyword" + }, + "targetId": { + "type": "keyword" + }, + "resolveCounter": { + "type": "integer" + }, + "lastResolved": { + "type": "date" + } + } + }, + "config": { + "dynamic": "true", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "alert": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "config": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "space": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "originId": { + "type": "keyword" + }, + "coreMigrationVersion": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "search": { + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "imageUrl": { + "index": false, + "type": "text" + }, + "initials": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} From 80c152c0eb83c90a2292651b615c8ab005c348bd Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Tue, 12 Oct 2021 12:37:21 -0400 Subject: [PATCH 71/73] [Observability] [Exploratory View] add percentile ranks, show legend always, and fix field labels (#113765) * add percentile ranks, show legend always, and fix field labels * add 50th percentile * replace hard coded values with constant Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../configurations/constants/constants.ts | 16 ++++- .../configurations/lens_attributes.test.ts | 61 ++++++++++++++++++- .../configurations/lens_attributes.ts | 57 +++++++++++++++-- .../rum/kpi_over_time_config.ts | 2 + .../synthetics/kpi_over_time_config.ts | 12 +++- .../test_data/sample_attribute.ts | 1 + .../test_data/sample_attribute_cwv.ts | 1 + .../test_data/sample_attribute_kpi.ts | 1 + .../breakdown/breakdowns.test.tsx | 21 +++++++ .../series_editor/breakdown/breakdowns.tsx | 20 ++++-- .../expanded_series_row.test.tsx | 40 ++++++++++++ .../series_editor/expanded_series_row.tsx | 6 +- 12 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index 68dcd77e98990..e4473b183d729 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { OperationType } from '../../../../../../../lens/public'; import { ReportViewType } from '../../types'; import { CLS_FIELD, @@ -13,6 +13,7 @@ import { LCP_FIELD, TBT_FIELD, TRANSACTION_TIME_TO_FIRST_BYTE, + TRANSACTION_DURATION, } from './elasticsearch_fieldnames'; import { AGENT_HOST_LABEL, @@ -45,6 +46,8 @@ import { TBT_LABEL, URL_LABEL, BACKEND_TIME_LABEL, + MONITORS_DURATION_LABEL, + PAGE_LOAD_TIME_LABEL, LABELS_FIELD, } from './labels'; @@ -69,9 +72,11 @@ export const FieldLabels: Record = { [FID_FIELD]: FID_LABEL, [CLS_FIELD]: CLS_LABEL, [TRANSACTION_TIME_TO_FIRST_BYTE]: BACKEND_TIME_LABEL, + [TRANSACTION_DURATION]: PAGE_LOAD_TIME_LABEL, 'monitor.id': MONITOR_ID_LABEL, 'monitor.status': MONITOR_STATUS_LABEL, + 'monitor.duration.us': MONITORS_DURATION_LABEL, 'agent.hostname': AGENT_HOST_LABEL, 'host.hostname': HOST_NAME_LABEL, @@ -86,6 +91,7 @@ export const FieldLabels: Record = { 'performance.metric': METRIC_LABEL, 'Business.KPI': KPI_LABEL, 'http.request.method': REQUEST_METHOD, + percentile: 'Percentile', LABEL_FIELDS_FILTER: LABELS_FIELD, LABEL_FIELDS_BREAKDOWN: 'Labels field', }; @@ -114,8 +120,16 @@ export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN'; export const FILTER_RECORDS = 'FILTER_RECORDS'; export const TERMS_COLUMN = 'TERMS_COLUMN'; export const OPERATION_COLUMN = 'operation'; +export const PERCENTILE = 'percentile'; export const REPORT_METRIC_FIELD = 'REPORT_METRIC_FIELD'; +export const PERCENTILE_RANKS = [ + '99th' as OperationType, + '95th' as OperationType, + '90th' as OperationType, + '75th' as OperationType, + '50th' as OperationType, +]; export const LABEL_FIELDS_FILTER = 'LABEL_FIELDS_FILTER'; export const LABEL_FIELDS_BREAKDOWN = 'LABEL_FIELDS_BREAKDOWN'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index 2781c26954234..139f9fe67c751 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -16,7 +16,7 @@ import { } from './constants/elasticsearch_fieldnames'; import { buildExistsFilter, buildPhrasesFilter } from './utils'; import { sampleAttributeKpi } from './test_data/sample_attribute_kpi'; -import { RECORDS_FIELD, REPORT_METRIC_FIELD, ReportTypes } from './constants'; +import { RECORDS_FIELD, REPORT_METRIC_FIELD, PERCENTILE_RANKS, ReportTypes } from './constants'; describe('Lens Attribute', () => { mockAppIndexPattern(); @@ -75,6 +75,63 @@ describe('Lens Attribute', () => { expect(lnsAttrKpi.getJSON()).toEqual(sampleAttributeKpi); }); + it('should return expected json for percentile breakdowns', function () { + const seriesConfigKpi = getDefaultConfigs({ + reportType: ReportTypes.KPI, + dataType: 'ux', + indexPattern: mockIndexPattern, + }); + + const lnsAttrKpi = new LensAttributes([ + { + filters: [], + seriesConfig: seriesConfigKpi, + time: { + from: 'now-1h', + to: 'now', + }, + indexPattern: mockIndexPattern, + name: 'ux-series-1', + breakdown: 'percentile', + reportDefinitions: {}, + selectedMetricField: 'transaction.duration.us', + color: '#54b399', + }, + ]); + + expect(lnsAttrKpi.getJSON().state.datasourceStates.indexpattern.layers.layer0.columns).toEqual({ + 'x-axis-column-layer0': { + dataType: 'date', + isBucketed: true, + label: '@timestamp', + operationType: 'date_histogram', + params: { + interval: 'auto', + }, + scale: 'interval', + sourceField: '@timestamp', + }, + ...PERCENTILE_RANKS.reduce((acc: Record, rank, index) => { + acc[`y-axis-column-${index === 0 ? 'layer' + index : index}`] = { + dataType: 'number', + filter: { + language: 'kuery', + query: 'transaction.type: page-load and processor.event: transaction', + }, + isBucketed: false, + label: `${rank} percentile of page load time`, + operationType: 'percentile', + params: { + percentile: Number(rank.slice(0, 2)), + }, + scale: 'ratio', + sourceField: 'transaction.duration.us', + }; + return acc; + }, {}), + }); + }); + it('should return main y axis', function () { expect(lnsAttr.getMainYAxis(layerConfig, 'layer0', '')).toEqual({ dataType: 'number', @@ -413,7 +470,7 @@ describe('Lens Attribute', () => { yConfig: [{ color: 'green', forAccessor: 'y-axis-column-layer0' }], }, ], - legend: { isVisible: true, position: 'right' }, + legend: { isVisible: true, showSingleSeries: true, position: 'right' }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, valueLabels: 'hide', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index fa5a8beb0087d..e3dab3c4e91f0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -37,6 +37,8 @@ import { REPORT_METRIC_FIELD, RECORDS_FIELD, RECORDS_PERCENTAGE_FIELD, + PERCENTILE, + PERCENTILE_RANKS, ReportTypes, } from './constants'; import { ColumnFilter, SeriesConfig, UrlFilter, URLReportDefinition } from '../types'; @@ -249,6 +251,30 @@ export class LensAttributes { }; } + getPercentileBreakdowns( + layerConfig: LayerConfig, + columnFilter?: string + ): Record { + const yAxisColumns = layerConfig.seriesConfig.yAxisColumns; + const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0]; + const lensColumns: Record = {}; + + // start at 1, because main y axis will have the first percentile breakdown + for (let i = 1; i < PERCENTILE_RANKS.length; i++) { + lensColumns[`y-axis-column-${i}`] = { + ...this.getColumnBasedOnType({ + sourceField: mainSourceField!, + operationType: PERCENTILE_RANKS[i], + label: mainLabel, + layerConfig, + colIndex: i, + }), + filter: { query: columnFilter || '', language: 'kuery' }, + }; + } + return lensColumns; + } + getPercentileNumberColumn( sourceField: string, percentileValue: string, @@ -258,7 +284,7 @@ export class LensAttributes { ...buildNumberColumn(sourceField), label: i18n.translate('xpack.observability.expView.columns.label', { defaultMessage: '{percentileValue} percentile of {sourceField}', - values: { sourceField: seriesConfig.labels[sourceField], percentileValue }, + values: { sourceField: seriesConfig.labels[sourceField]?.toLowerCase(), percentileValue }, }), operationType: 'percentile', params: { percentile: Number(percentileValue.split('th')[0]) }, @@ -328,6 +354,7 @@ export class LensAttributes { layerConfig: LayerConfig; colIndex?: number; }) { + const { breakdown, seriesConfig } = layerConfig; const { fieldMeta, columnType, fieldName, columnLabel, timeScale, columnFilters } = this.getFieldMeta(sourceField, layerConfig); @@ -348,6 +375,18 @@ export class LensAttributes { if (fieldType === 'date') { return this.getDateHistogramColumn(fieldName); } + + if (fieldType === 'number' && breakdown === PERCENTILE) { + return { + ...this.getPercentileNumberColumn( + fieldName, + operationType || PERCENTILE_RANKS[0], + seriesConfig! + ), + filter: colIndex !== undefined ? columnFilters?.[colIndex] : undefined, + }; + } + if (fieldType === 'number') { return this.getNumberColumn({ sourceField: fieldName, @@ -395,6 +434,7 @@ export class LensAttributes { } getMainYAxis(layerConfig: LayerConfig, layerId: string, columnFilter: string) { + const { breakdown } = layerConfig; const { sourceField, operationType, label } = layerConfig.seriesConfig.yAxisColumns[0]; if (sourceField === RECORDS_PERCENTAGE_FIELD) { @@ -407,7 +447,7 @@ export class LensAttributes { return this.getColumnBasedOnType({ sourceField, - operationType, + operationType: breakdown === PERCENTILE ? PERCENTILE_RANKS[0] : operationType, label, layerConfig, colIndex: 0, @@ -415,6 +455,7 @@ export class LensAttributes { } getChildYAxises(layerConfig: LayerConfig, layerId?: string, columnFilter?: string) { + const { breakdown } = layerConfig; const lensColumns: Record = {}; const yAxisColumns = layerConfig.seriesConfig.yAxisColumns; const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0]; @@ -424,7 +465,10 @@ export class LensAttributes { .supportingColumns; } - // 1 means there is only main y axis + if (yAxisColumns.length === 1 && breakdown === PERCENTILE) { + return this.getPercentileBreakdowns(layerConfig, columnFilter); + } + if (yAxisColumns.length === 1) { return lensColumns; } @@ -574,7 +618,7 @@ export class LensAttributes { layers[layerId] = { columnOrder: [ `x-axis-column-${layerId}`, - ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN + ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN && breakdown !== PERCENTILE ? [`breakdown-column-${layerId}`] : []), `y-axis-column-${layerId}`, @@ -588,7 +632,7 @@ export class LensAttributes { filter: { query: columnFilter, language: 'kuery' }, ...(timeShift ? { timeShift } : {}), }, - ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN + ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN && breakdown !== PERCENTILE ? // do nothing since this will be used a x axis source { [`breakdown-column-${layerId}`]: this.getBreakdownColumn({ @@ -610,7 +654,7 @@ export class LensAttributes { getXyState(): XYState { return { - legend: { isVisible: true, position: 'right' }, + legend: { isVisible: true, showSingleSeries: true, position: 'right' }, valueLabels: 'hide', fittingFunction: 'Linear', curveType: 'CURVE_MONOTONE_X' as XYCurveType, @@ -636,6 +680,7 @@ export class LensAttributes { ], xAccessor: `x-axis-column-layer${index}`, ...(layerConfig.breakdown && + layerConfig.breakdown !== PERCENTILE && layerConfig.seriesConfig.xAxisColumn.sourceField !== USE_BREAK_DOWN_COLUMN ? { splitAccessor: `breakdown-column-layer${index}` } : {}), diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts index de4f6b2198dbd..000e50d7b3a52 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts @@ -13,6 +13,7 @@ import { OPERATION_COLUMN, RECORDS_FIELD, REPORT_METRIC_FIELD, + PERCENTILE, ReportTypes, } from '../constants'; import { buildPhraseFilter } from '../utils'; @@ -81,6 +82,7 @@ export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): SeriesCon USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE, + PERCENTILE, LABEL_FIELDS_BREAKDOWN, ], baseFilters: [ diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts index 65b43a83a8fb5..6df9cdcd0503a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts @@ -6,7 +6,13 @@ */ import { ConfigProps, SeriesConfig } from '../../types'; -import { FieldLabels, OPERATION_COLUMN, REPORT_METRIC_FIELD, ReportTypes } from '../constants'; +import { + FieldLabels, + OPERATION_COLUMN, + REPORT_METRIC_FIELD, + PERCENTILE, + ReportTypes, +} from '../constants'; import { CLS_LABEL, DCL_LABEL, @@ -44,7 +50,7 @@ export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): SeriesCon ], hasOperationType: false, filterFields: ['observer.geo.name', 'monitor.type', 'tags'], - breakdownFields: ['observer.geo.name', 'monitor.type', 'monitor.name'], + breakdownFields: ['observer.geo.name', 'monitor.type', 'monitor.name', PERCENTILE], baseFilters: [], palette: { type: 'palette', name: 'status' }, definitionFields: ['monitor.name', 'url.full'], @@ -98,6 +104,6 @@ export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): SeriesCon columnType: OPERATION_COLUMN, }, ], - labels: { ...FieldLabels }, + labels: { ...FieldLabels, [SUMMARY_UP]: UP_LABEL, [SUMMARY_DOWN]: DOWN_LABEL }, }; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts index 7e0ea1e575481..8254a5a816921 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts @@ -187,6 +187,7 @@ export const sampleAttribute = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts index dff3d6b3ad5ef..adc6d4bb14462 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts @@ -134,6 +134,7 @@ export const sampleAttributeCoreWebVital = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts index 6ed9b4face6e3..8fbda9f6adc52 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts @@ -89,6 +89,7 @@ export const sampleAttributeKpi = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx index cb683119384d9..8ed279ace28f6 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx @@ -10,6 +10,7 @@ import { fireEvent, screen } from '@testing-library/react'; import { Breakdowns } from './breakdowns'; import { mockIndexPattern, mockUxSeries, render } from '../../rtl_helpers'; import { getDefaultConfigs } from '../../configurations/default_configs'; +import { RECORDS_FIELD } from '../../configurations/constants'; import { USER_AGENT_OS } from '../../configurations/constants/elasticsearch_fieldnames'; describe('Breakdowns', function () { @@ -56,6 +57,26 @@ describe('Breakdowns', function () { expect(setSeries).toHaveBeenCalledTimes(1); }); + it('does not show percentile breakdown for records metrics', function () { + const kpiConfig = getDefaultConfigs({ + reportType: 'kpi-over-time', + indexPattern: mockIndexPattern, + dataType: 'ux', + }); + + render( + + ); + + fireEvent.click(screen.getByTestId('seriesBreakdown')); + + expect(screen.queryByText('Percentile')).not.toBeInTheDocument(); + }); + it('should disable breakdowns when a different series has a breakdown', function () { const initSeries = { data: [mockUxSeries, { ...mockUxSeries, breakdown: undefined }], diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx index 7964abdeeddc5..a235cbd8852ad 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx @@ -10,7 +10,12 @@ import styled from 'styled-components'; import { EuiSuperSelect, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useSeriesStorage } from '../../hooks/use_series_storage'; -import { LABEL_FIELDS_BREAKDOWN, USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; +import { + LABEL_FIELDS_BREAKDOWN, + USE_BREAK_DOWN_COLUMN, + RECORDS_FIELD, + PERCENTILE, +} from '../../configurations/constants'; import { SeriesConfig, SeriesUrl } from '../../types'; interface Props { @@ -51,6 +56,7 @@ export function Breakdowns({ seriesConfig, seriesId, series }: Props) { } const hasUseBreakdownColumn = seriesConfig.xAxisColumn.sourceField === USE_BREAK_DOWN_COLUMN; + const isRecordsMetric = series.selectedMetricField === RECORDS_FIELD; const items = seriesConfig.breakdownFields.map((breakdown) => ({ id: breakdown, @@ -64,11 +70,13 @@ export function Breakdowns({ seriesConfig, seriesId, series }: Props) { }); } - const options = items.map(({ id, label }) => ({ - inputDisplay: label, - value: id, - dropdownDisplay: label, - })); + const options = items + .map(({ id, label }) => ({ + inputDisplay: label, + value: id, + dropdownDisplay: label, + })) + .filter(({ value }) => !(value === PERCENTILE && isRecordsMetric)); let valueOfSelected = selectedBreakdown || (hasUseBreakdownColumn ? options[0].value : NO_BREAKDOWN); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx new file mode 100644 index 0000000000000..83958840f63d9 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen } from '@testing-library/react'; +import { ExpandedSeriesRow } from './expanded_series_row'; +import { mockIndexPattern, mockUxSeries, render } from '../rtl_helpers'; +import { getDefaultConfigs } from '../configurations/default_configs'; +import { PERCENTILE } from '../configurations/constants'; + +describe('ExpandedSeriesRow', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'kpi-over-time', + indexPattern: mockIndexPattern, + dataType: 'ux', + }); + + it('should render properly', async function () { + render(); + + expect(screen.getByText('Breakdown by')).toBeInTheDocument(); + expect(screen.getByText('Operation')).toBeInTheDocument(); + }); + + it('should not display operation field when percentile breakdowns are applied', async function () { + render( + + ); + + expect(screen.queryByText('Operation')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx index ac71f4ff5abe0..180be1ac0414f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiHorizontalRule } from '@elastic/eui'; import { SeriesConfig, SeriesUrl } from '../types'; +import { PERCENTILE } from '../configurations/constants'; import { ReportDefinitionCol } from './columns/report_definition_col'; import { OperationTypeSelect } from './columns/operation_type_select'; import { parseCustomFieldName } from '../configurations/lens_attributes'; @@ -42,6 +43,9 @@ export function ExpandedSeriesRow(seriesProps: Props) { const columnType = getColumnType(seriesConfig, selectedMetricField); + // if the breakdown field is percentiles, we can't apply further operations + const hasPercentileBreakdown = series.breakdown === PERCENTILE; + return (
@@ -69,7 +73,7 @@ export function ExpandedSeriesRow(seriesProps: Props) { - {(hasOperationType || columnType === 'operation') && ( + {(hasOperationType || (columnType === 'operation' && !hasPercentileBreakdown)) && ( Date: Tue, 12 Oct 2021 12:39:43 -0400 Subject: [PATCH 72/73] [Uptime] [Synthetics Integration] add new advanced options (#112454) * refactor common fields * add ignore_https_errors and journey filters options * adjust formatters and normalizers * adjust content and hide fields when zip url is not defined * adjust content again * update tests * adjust tests * adjust tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../browser/advanced_fields.test.tsx | 45 ++++++- .../fleet_package/browser/advanced_fields.tsx | 102 +++++++++++++++- .../fleet_package/browser/formatters.ts | 5 + .../fleet_package/browser/normalizers.ts | 7 ++ .../fleet_package/browser/simple_fields.tsx | 93 +------------- .../fleet_package/common/common_fields.tsx | 113 ++++++++++++++++++ .../contexts/browser_context_advanced.tsx | 3 + ..._context.tsx => http_context_advanced.tsx} | 0 .../fleet_package/contexts/index.ts | 4 +- ...p_context.tsx => tcp_context_advanced.tsx} | 0 .../fleet_package/http/simple_fields.tsx | 92 +------------- .../fleet_package/icmp/simple_fields.tsx | 90 +------------- .../fleet_package/tcp/simple_fields.tsx | 93 +------------- .../public/components/fleet_package/types.tsx | 8 +- 14 files changed, 289 insertions(+), 366 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/fleet_package/common/common_fields.tsx rename x-pack/plugins/uptime/public/components/fleet_package/contexts/{advanced_fields_http_context.tsx => http_context_advanced.tsx} (100%) rename x-pack/plugins/uptime/public/components/fleet_package/contexts/{advanced_fields_tcp_context.tsx => tcp_context_advanced.tsx} (100%) diff --git a/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.test.tsx index aa1f7ca07e3d8..fabf6da49cf47 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.test.tsx @@ -9,10 +9,12 @@ import React from 'react'; import { fireEvent } from '@testing-library/react'; import { render } from '../../../lib/helper/rtl_helpers'; import { BrowserAdvancedFields } from './advanced_fields'; -import { ConfigKeys, IBrowserAdvancedFields } from '../types'; +import { ConfigKeys, IBrowserAdvancedFields, IBrowserSimpleFields } from '../types'; import { BrowserAdvancedFieldsContextProvider, + BrowserSimpleFieldsContextProvider, defaultBrowserAdvancedFields as defaultConfig, + defaultBrowserSimpleFields, } from '../contexts'; jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ @@ -20,11 +22,19 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ })); describe('', () => { - const WrappedComponent = ({ defaultValues }: { defaultValues?: IBrowserAdvancedFields }) => { + const WrappedComponent = ({ + defaultValues = defaultConfig, + defaultSimpleFields = defaultBrowserSimpleFields, + }: { + defaultValues?: IBrowserAdvancedFields; + defaultSimpleFields?: IBrowserSimpleFields; + }) => { return ( - - - + + + + + ); }; @@ -46,4 +56,29 @@ describe('', () => { expect(screenshots.value).toEqual('off'); }); + + it('only displayed filter options when zip url is truthy', () => { + const { queryByText, getByText, rerender } = render(); + + expect( + queryByText( + /Use these options to apply the selected monitor settings to a subset of the tests in your suite./ + ) + ).not.toBeInTheDocument(); + + rerender( + + ); + + expect( + getByText( + /Use these options to apply the selected monitor settings to a subset of the tests in your suite./ + ) + ).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.tsx index 28e2e39c79554..61af9f8ec6143 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/browser/advanced_fields.tsx @@ -10,13 +10,15 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiAccordion, EuiSelect, + EuiFieldText, + EuiCheckbox, EuiFormRow, EuiDescribedFormGroup, EuiSpacer, } from '@elastic/eui'; import { ComboBox } from '../combo_box'; -import { useBrowserAdvancedFieldsContext } from '../contexts'; +import { useBrowserAdvancedFieldsContext, useBrowserSimpleFieldsContext } from '../contexts'; import { ConfigKeys, ScreenshotOption } from '../types'; @@ -24,6 +26,7 @@ import { OptionalLabel } from '../optional_label'; export const BrowserAdvancedFields = () => { const { fields, setFields } = useBrowserAdvancedFieldsContext(); + const { fields: simpleFields } = useBrowserSimpleFieldsContext(); const handleInputChange = useCallback( ({ value, configKey }: { value: unknown; configKey: ConfigKeys }) => { @@ -39,6 +42,75 @@ export const BrowserAdvancedFields = () => { data-test-subj="syntheticsBrowserAdvancedFieldsAccordion" > + {simpleFields[ConfigKeys.SOURCE_ZIP_URL] && ( + + +

+ } + description={ + + } + > + + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.JOURNEY_FILTERS_MATCH, + }) + } + data-test-subj="syntheticsBrowserJourneyFiltersMatch" + /> + + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ value, configKey: ConfigKeys.JOURNEY_FILTERS_TAGS }) + } + data-test-subj="syntheticsBrowserJourneyFiltersTags" + /> + + + )} @@ -56,6 +128,34 @@ export const BrowserAdvancedFields = () => { } > + + + + } + data-test-subj="syntheticsBrowserIgnoreHttpsErrors" + > + + } + onChange={(event) => + handleInputChange({ + value: event.target.checked, + configKey: ConfigKeys.IGNORE_HTTPS_ERRORS, + }) + } + /> + arrayToJsonFormatter(fields[ConfigKeys.SYNTHETICS_ARGS]), + [ConfigKeys.JOURNEY_FILTERS_MATCH]: (fields) => + stringToJsonFormatter(fields[ConfigKeys.JOURNEY_FILTERS_MATCH]), + [ConfigKeys.JOURNEY_FILTERS_TAGS]: (fields) => + arrayToJsonFormatter(fields[ConfigKeys.JOURNEY_FILTERS_TAGS]), + [ConfigKeys.IGNORE_HTTPS_ERRORS]: null, ...commonFormatters, }; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/browser/normalizers.ts b/x-pack/plugins/uptime/public/components/fleet_package/browser/normalizers.ts index 53bbf611d490c..0107fb3884f41 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/browser/normalizers.ts +++ b/x-pack/plugins/uptime/public/components/fleet_package/browser/normalizers.ts @@ -39,5 +39,12 @@ export const browserNormalizers: BrowserNormalizerMap = { [ConfigKeys.PARAMS]: getBrowserNormalizer(ConfigKeys.PARAMS), [ConfigKeys.SCREENSHOTS]: getBrowserNormalizer(ConfigKeys.SCREENSHOTS), [ConfigKeys.SYNTHETICS_ARGS]: getBrowserJsonToJavascriptNormalizer(ConfigKeys.SYNTHETICS_ARGS), + [ConfigKeys.JOURNEY_FILTERS_MATCH]: getBrowserJsonToJavascriptNormalizer( + ConfigKeys.JOURNEY_FILTERS_MATCH + ), + [ConfigKeys.JOURNEY_FILTERS_TAGS]: getBrowserJsonToJavascriptNormalizer( + ConfigKeys.JOURNEY_FILTERS_TAGS + ), + [ConfigKeys.IGNORE_HTTPS_ERRORS]: getBrowserNormalizer(ConfigKeys.IGNORE_HTTPS_ERRORS), ...commonNormalizers, }; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/browser/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/browser/simple_fields.tsx index 0e2f10b96fe6d..7c7a6b199adcb 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/browser/simple_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/browser/simple_fields.tsx @@ -7,13 +7,12 @@ import React, { memo, useMemo, useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { EuiFormRow } from '@elastic/eui'; import { ConfigKeys, Validation } from '../types'; import { useBrowserSimpleFieldsContext } from '../contexts'; -import { ComboBox } from '../combo_box'; -import { OptionalLabel } from '../optional_label'; import { ScheduleField } from '../schedule_field'; import { SourceField } from './source_field'; +import { CommonFields } from '../common/common_fields'; interface Props { validate: Validation; @@ -91,93 +90,7 @@ export const BrowserSimpleFields = memo(({ validate }) => { )} /> - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.APM_SERVICE_NAME, - }) - } - data-test-subj="syntheticsAPMServiceName" - /> - - - } - isInvalid={!!validate[ConfigKeys.TIMEOUT]?.(fields)} - error={ - parseInt(fields[ConfigKeys.TIMEOUT], 10) < 0 ? ( - - ) : ( - - ) - } - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.TIMEOUT, - }) - } - step={'any'} - /> - - - } - labelAppend={} - helpText={ - - } - > - handleInputChange({ value, configKey: ConfigKeys.TAGS })} - data-test-subj="syntheticsTags" - /> - + ); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/common/common_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/common/common_fields.tsx new file mode 100644 index 0000000000000..57d5094958ca3 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/common/common_fields.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { ConfigKeys, Validation, ICommonFields } from '../types'; +import { ComboBox } from '../combo_box'; +import { OptionalLabel } from '../optional_label'; + +interface Props { + validate: Validation; + fields: ICommonFields; + onChange: ({ value, configKey }: { value: string | string[]; configKey: ConfigKeys }) => void; +} + +export function CommonFields({ fields, onChange, validate }: Props) { + return ( + <> + + } + labelAppend={} + helpText={ + + } + > + + onChange({ + value: event.target.value, + configKey: ConfigKeys.APM_SERVICE_NAME, + }) + } + data-test-subj="syntheticsAPMServiceName" + /> + + + } + isInvalid={!!validate[ConfigKeys.TIMEOUT]?.(fields)} + error={ + parseInt(fields[ConfigKeys.TIMEOUT], 10) < 0 ? ( + + ) : ( + + ) + } + helpText={ + + } + > + + onChange({ + value: event.target.value, + configKey: ConfigKeys.TIMEOUT, + }) + } + step={'any'} + /> + + + } + labelAppend={} + helpText={ + + } + > + onChange({ value, configKey: ConfigKeys.TAGS })} + data-test-subj="syntheticsTags" + /> + + + ); +} diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/browser_context_advanced.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/browser_context_advanced.tsx index 3f3bb8f14c269..bc766462f18ae 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/contexts/browser_context_advanced.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/browser_context_advanced.tsx @@ -22,6 +22,9 @@ interface IBrowserAdvancedFieldsContextProvider { export const initialValues: IBrowserAdvancedFields = { [ConfigKeys.SCREENSHOTS]: ScreenshotOption.ON, [ConfigKeys.SYNTHETICS_ARGS]: [], + [ConfigKeys.JOURNEY_FILTERS_MATCH]: '', + [ConfigKeys.JOURNEY_FILTERS_TAGS]: [], + [ConfigKeys.IGNORE_HTTPS_ERRORS]: false, }; const defaultContext: IBrowserAdvancedFieldsContext = { diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/advanced_fields_http_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_context_advanced.tsx similarity index 100% rename from x-pack/plugins/uptime/public/components/fleet_package/contexts/advanced_fields_http_context.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/contexts/http_context_advanced.tsx diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts b/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts index e955d2d7d4d50..4d76a6d8f8d67 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts @@ -21,7 +21,7 @@ export { HTTPAdvancedFieldsContextProvider, initialValues as defaultHTTPAdvancedFields, useHTTPAdvancedFieldsContext, -} from './advanced_fields_http_context'; +} from './http_context_advanced'; export { TCPSimpleFieldsContext, TCPSimpleFieldsContextProvider, @@ -39,7 +39,7 @@ export { TCPAdvancedFieldsContextProvider, initialValues as defaultTCPAdvancedFields, useTCPAdvancedFieldsContext, -} from './advanced_fields_tcp_context'; +} from './tcp_context_advanced'; export { BrowserSimpleFieldsContext, BrowserSimpleFieldsContextProvider, diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/advanced_fields_tcp_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_context_advanced.tsx similarity index 100% rename from x-pack/plugins/uptime/public/components/fleet_package/contexts/advanced_fields_tcp_context.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_context_advanced.tsx diff --git a/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx index c4de1d53fe998..90f94324fe657 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx @@ -10,9 +10,9 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; import { ConfigKeys, Validation } from '../types'; import { useHTTPSimpleFieldsContext } from '../contexts'; -import { ComboBox } from '../combo_box'; import { OptionalLabel } from '../optional_label'; import { ScheduleField } from '../schedule_field'; +import { CommonFields } from '../common/common_fields'; interface Props { validate: Validation; @@ -50,7 +50,7 @@ export const HTTPSimpleFields = memo(({ validate }) => { /> (({ validate }) => { unit={fields[ConfigKeys.SCHEDULE].unit} /> - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.APM_SERVICE_NAME, - }) - } - data-test-subj="syntheticsAPMServiceName" - /> - (({ validate }) => { } /> - - } - isInvalid={!!validate[ConfigKeys.TIMEOUT]?.(fields)} - error={ - parseInt(fields[ConfigKeys.TIMEOUT], 10) < 0 ? ( - - ) : ( - - ) - } - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.TIMEOUT, - }) - } - step={'any'} - /> - - - } - labelAppend={} - helpText={ - - } - > - handleInputChange({ value, configKey: ConfigKeys.TAGS })} - data-test-subj="syntheticsTags" - /> - + ); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx index 92afe4c5072e1..32c843f1ce114 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx @@ -10,9 +10,9 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; import { ConfigKeys, Validation } from '../types'; import { useICMPSimpleFieldsContext } from '../contexts'; -import { ComboBox } from '../combo_box'; import { OptionalLabel } from '../optional_label'; import { ScheduleField } from '../schedule_field'; +import { CommonFields } from '../common/common_fields'; interface Props { validate: Validation; @@ -113,93 +113,7 @@ export const ICMPSimpleFields = memo(({ validate }) => { step={'any'} /> - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.APM_SERVICE_NAME, - }) - } - data-test-subj="syntheticsAPMServiceName" - /> - - - } - isInvalid={!!validate[ConfigKeys.TIMEOUT]?.(fields)} - error={ - parseInt(fields[ConfigKeys.TIMEOUT], 10) < 0 ? ( - - ) : ( - - ) - } - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.TIMEOUT, - }) - } - step={'any'} - /> - - - } - labelAppend={} - helpText={ - - } - > - handleInputChange({ value, configKey: ConfigKeys.TAGS })} - data-test-subj="syntheticsTags" - /> - + ); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx index 37f0c82595e02..53a0074a47d73 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx @@ -7,12 +7,11 @@ import React, { memo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { EuiFormRow, EuiFieldText } from '@elastic/eui'; import { ConfigKeys, Validation } from '../types'; import { useTCPSimpleFieldsContext } from '../contexts'; -import { ComboBox } from '../combo_box'; -import { OptionalLabel } from '../optional_label'; import { ScheduleField } from '../schedule_field'; +import { CommonFields } from '../common/common_fields'; interface Props { validate: Validation; @@ -80,93 +79,7 @@ export const TCPSimpleFields = memo(({ validate }) => { unit={fields[ConfigKeys.SCHEDULE].unit} /> - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.APM_SERVICE_NAME, - }) - } - data-test-subj="syntheticsAPMServiceName" - /> - - - } - isInvalid={!!validate[ConfigKeys.TIMEOUT]?.(fields)} - error={ - parseInt(fields[ConfigKeys.TIMEOUT], 10) < 0 ? ( - - ) : ( - - ) - } - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.TIMEOUT, - }) - } - step={'any'} - /> - - - } - labelAppend={} - helpText={ - - } - > - handleInputChange({ value, configKey: ConfigKeys.TAGS })} - data-test-subj="syntheticsTags" - /> - + ); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/types.tsx b/x-pack/plugins/uptime/public/components/fleet_package/types.tsx index 89581bf993339..db736f1bae4d2 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/types.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/types.tsx @@ -76,9 +76,13 @@ export enum ScreenshotOption { export enum ConfigKeys { APM_SERVICE_NAME = 'service.name', HOSTS = 'hosts', + IGNORE_HTTPS_ERRORS = 'ignore_https_errors', + JOURNEY_FILTERS_MATCH = 'filter_journeys.match', + JOURNEY_FILTERS_TAGS = 'filter_journeys.tags', MAX_REDIRECTS = 'max_redirects', MONITOR_TYPE = 'type', NAME = 'name', + PARAMS = 'params', PASSWORD = 'password', PROXY_URL = 'proxy_url', PROXY_USE_LOCAL_RESOLVER = 'proxy_use_local_resolver', @@ -101,7 +105,6 @@ export enum ConfigKeys { SOURCE_ZIP_PASSWORD = 'source.zip_url.password', SOURCE_ZIP_FOLDER = 'source.zip_url.folder', SYNTHETICS_ARGS = 'synthetics_args', - PARAMS = 'params', TLS_CERTIFICATE_AUTHORITIES = 'ssl.certificate_authorities', TLS_CERTIFICATE = 'ssl.certificate', TLS_KEY = 'ssl.key', @@ -198,6 +201,9 @@ export type IBrowserSimpleFields = { export interface IBrowserAdvancedFields { [ConfigKeys.SYNTHETICS_ARGS]: string[]; [ConfigKeys.SCREENSHOTS]: string; + [ConfigKeys.JOURNEY_FILTERS_MATCH]: string; + [ConfigKeys.JOURNEY_FILTERS_TAGS]: string[]; + [ConfigKeys.IGNORE_HTTPS_ERRORS]: boolean; } export type HTTPFields = IHTTPSimpleFields & IHTTPAdvancedFields & ITLSFields; From 7c6db7534b1f07b34722d68458206039cda650f6 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Tue, 12 Oct 2021 13:25:35 -0400 Subject: [PATCH 73/73] Adding functional test --- .../task_runner/task_runner_cancel.test.ts | 1 + .../plugins/alerts/server/alert_types.ts | 52 ++++++ .../alerting/builtin_alert_types/index.ts | 1 + .../builtin_alert_types/long_running/index.ts | 15 ++ .../builtin_alert_types/long_running/rule.ts | 161 ++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/index.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/rule.ts diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index 9467425f67962..14c4c88fbb567 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -296,6 +296,7 @@ describe('Task Runner Cancel', () => { message: `rule execution cancelled due to timeout: "test1"`, reason: 'timeout', }, + lastDuration: 0, lastExecutionDate: '1970-01-01T00:00:00.000Z', status: 'error', }, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index 7978d6c82025f..00adf916bb713 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -465,6 +465,56 @@ function getPatternFiringAlertType() { return result; } +function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true) { + const paramsSchema = schema.object({ + pattern: schema.arrayOf(schema.boolean()), + }); + type ParamsType = TypeOf; + interface State extends AlertTypeState { + patternIndex?: number; + } + const result: AlertType = { + id: `test.patternLongRunning${ + cancelAlertsOnRuleTimeout === true ? '.cancelAlertsOnRuleTimeout' : '' + }`, + name: 'Test: Run Long on a Pattern', + actionGroups: [{ id: 'default', name: 'Default' }], + producer: 'alertsFixture', + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + ruleTaskTimeout: '3s', + cancelAlertsOnRuleTimeout, + async executor(ruleExecutorOptions) { + const { services, state, params } = ruleExecutorOptions; + const pattern = params.pattern; + if (!Array.isArray(pattern)) { + throw new Error(`pattern is not an array`); + } + + // await new Promise((resolve) => setTimeout(resolve, 5000)); + + // get the pattern index, return if past it + const patternIndex = state.patternIndex ?? 0; + if (patternIndex >= pattern.length) { + return { patternIndex }; + } + + // run long if pattern says to + if (pattern[patternIndex] === true) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + } + + services.alertInstanceFactory('alert').scheduleActions('default', {}); + + return { + patternIndex: patternIndex + 1, + }; + }, + }; + return result; +} + export function defineAlertTypes( core: CoreSetup, { alerting }: Pick @@ -579,4 +629,6 @@ export function defineAlertTypes( alerting.registerType(longRunningAlertType); alerting.registerType(goldNoopAlertType); alerting.registerType(exampleAlwaysFiringAlertType); + alerting.registerType(getLongRunningPatternRuleType()); + alerting.registerType(getLongRunningPatternRuleType(false)); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index.ts index 965cf352ab7ed..14748737f0d53 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index.ts @@ -12,5 +12,6 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { describe('builtin alertTypes', () => { loadTestFile(require.resolve('./index_threshold')); loadTestFile(require.resolve('./es_query')); + loadTestFile(require.resolve('./long_running')); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/index.ts new file mode 100644 index 0000000000000..d997cebc6fd8d --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function alertingTests({ loadTestFile }: FtrProviderContext) { + describe('long_running_rule', () => { + loadTestFile(require.resolve('./rule')); + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/rule.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/rule.ts new file mode 100644 index 0000000000000..d629080898fcb --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/long_running/rule.ts @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { Spaces } from '../../../../scenarios'; +import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getUrlPrefix, ObjectRemover, getEventLog } from '../../../../../common/lib'; + +const RULE_INTERVAL_SECONDS = 3; + +// eslint-disable-next-line import/no-default-export +export default function ruleTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const retry = getService('retry'); + + describe('rule', async () => { + const objectRemover = new ObjectRemover(supertest); + + afterEach(async () => { + await objectRemover.removeAll(); + }); + + it('writes event log document for timeout for each rule execution that ends in timeout - every execution times out', async () => { + const ruleId = await createRule({ + name: 'long running rule', + ruleTypeId: 'test.patternLongRunning.cancelAlertsOnRuleTimeout', + pattern: [true, true, true, true], + }); + // get the events we're expecting + const events = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: Spaces.space1.id, + type: 'alert', + id: ruleId, + provider: 'alerting', + actions: new Map([ + // make sure the counts of the # of events per type are as expected + ['execute-start', { gte: 4 }], + ['execute', { gte: 4 }], + ['execute-timeout', { gte: 4 }], + ]), + }); + }); + + // no active|recovered|new instance events should exist + expect(events.filter((event) => event?.event?.action === 'active-instance').length).to.equal( + 0 + ); + expect(events.filter((event) => event?.event?.action === 'new-instance').length).to.equal(0); + expect( + events.filter((event) => event?.event?.action === 'recovered-instance').length + ).to.equal(0); + + // rule execution status should be in error with reason timeout + const { status, body: rule } = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${ruleId}` + ); + expect(status).to.eql(200); + expect(rule.execution_status.status).to.eql('error'); + expect(rule.execution_status.error.message).to.eql( + `rule execution cancelled due to timeout: "test.patternLongRunning.cancelAlertsOnRuleTimeout${ruleId}"` + ); + expect(rule.execution_status.error.reason).to.eql('timeout'); + }); + + it('writes event log document for timeout for each rule execution that ends in timeout - some executions times out', async () => { + const ruleId = await createRule({ + name: 'long running rule', + ruleTypeId: 'test.patternLongRunning.cancelAlertsOnRuleTimeout', + pattern: [false, true, false, false], + }); + // get the events we're expecting + await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: Spaces.space1.id, + type: 'alert', + id: ruleId, + provider: 'alerting', + actions: new Map([ + // make sure the counts of the # of events per type are as expected + ['execute-start', { gte: 4 }], + ['execute', { gte: 4 }], + ['execute-timeout', { gte: 1 }], + ['new-instance', { equal: 1 }], + ['active-instance', { equal: 2 }], + ]), + }); + }); + + const { status, body: rule } = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${ruleId}` + ); + expect(status).to.eql(200); + expect(rule.execution_status.status).to.eql('active'); + }); + + it('still logs alert docs when rule exceeds timeout when cancelAlertsOnRuleTimeout is false on rule type', async () => { + const ruleId = await createRule({ + name: 'long running rule', + ruleTypeId: 'test.patternLongRunning', + pattern: [true, true, true, true], + }); + // get the events we're expecting + await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: Spaces.space1.id, + type: 'alert', + id: ruleId, + provider: 'alerting', + actions: new Map([ + // make sure the counts of the # of events per type are as expected + ['execute-start', { gte: 4 }], + ['execute', { gte: 4 }], + ['execute-timeout', { gte: 4 }], + ['new-instance', { gte: 1 }], + ['active-instance', { gte: 3 }], + ]), + }); + }); + }); + + interface CreateRuleParams { + name: string; + ruleTypeId: string; + pattern: boolean[]; + } + + async function createRule(params: CreateRuleParams): Promise { + const { status, body: createdRule } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send({ + name: params.name, + consumer: 'alerts', + enabled: true, + rule_type_id: params.ruleTypeId, + schedule: { interval: `${RULE_INTERVAL_SECONDS}s` }, + actions: [], + notify_when: 'onActiveAlert', + params: { + pattern: params.pattern, + }, + }); + + expect(status).to.be(200); + + const ruleId = createdRule.id; + objectRemover.add(Spaces.space1.id, ruleId, 'rule', 'alerting'); + + return ruleId; + } + }); +}